1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: no-exceptions 10 11 // This test file validates that std::vector<T>::reserve provides the strong exception guarantee if T is 12 // Cpp17MoveInsertable and no exception is thrown by the move constructor of T during the reserve call. 13 // It also checks that if T's move constructor is not noexcept, reserve provides only the basic exception 14 // guarantee. 15 16 #include <cstddef> 17 #include <memory> 18 #include <type_traits> 19 #include <vector> 20 21 #include "../common.h" 22 #include "MoveOnly.h" 23 #include "count_new.h" 24 #include "increasing_allocator.h" 25 #include "min_allocator.h" 26 #include "test_allocator.h" 27 #include "test_iterators.h" 28 #include "test_macros.h" 29 30 template <typename T, typename Alloc> 31 void test_allocation_exception_for_strong_guarantee( 32 std::vector<T, Alloc>& v, const std::vector<T>& values, std::size_t new_cap) { 33 assert(v.size() == values.size()); 34 T* old_data = v.data(); 35 std::size_t old_size = v.size(); 36 std::size_t old_cap = v.capacity(); 37 38 try { 39 v.reserve(new_cap); 40 } catch (...) { // std::length_error, std::bad_alloc 41 assert(v.data() == old_data); 42 assert(v.size() == old_size); 43 assert(v.capacity() == old_cap); 44 for (std::size_t i = 0; i < v.size(); ++i) 45 assert(v[i] == values[i]); 46 } 47 } 48 49 template <typename T, typename Alloc> 50 void test_copy_ctor_exception_for_strong_guarantee(std::vector<throwing_data<T>, Alloc>& v, 51 const std::vector<T>& values) { 52 assert(v.empty() && !values.empty()); 53 int throw_after = values.size() + values.size() / 2; // Trigger an exception halfway through reallocation 54 v.reserve(values.size()); 55 for (std::size_t i = 0; i < values.size(); ++i) 56 v.emplace_back(values[i], throw_after); 57 58 throwing_data<T>* old_data = v.data(); 59 std::size_t old_size = v.size(); 60 std::size_t old_cap = v.capacity(); 61 std::size_t new_cap = 2 * old_cap; 62 63 try { 64 v.reserve(new_cap); 65 } catch (...) { 66 assert(v.data() == old_data); 67 assert(v.size() == old_size); 68 assert(v.capacity() == old_cap); 69 for (std::size_t i = 0; i < v.size(); ++i) 70 assert(v[i].data_ == values[i]); 71 } 72 } 73 74 #if TEST_STD_VER >= 11 75 76 template <typename T, typename Alloc> 77 void test_move_ctor_exception_for_basic_guarantee(std::vector<move_only_throwing_t<T>, Alloc>& v, 78 const std::vector<T>& values) { 79 assert(v.empty() && !values.empty()); 80 int throw_after = values.size() + values.size() / 2; // Trigger an exception halfway through reallocation 81 v.reserve(values.size()); 82 for (std::size_t i = 0; i < values.size(); ++i) 83 v.emplace_back(values[i], throw_after); 84 85 try { 86 v.reserve(2 * v.capacity()); 87 } catch (...) { 88 use_unspecified_but_valid_state_vector(v); 89 } 90 } 91 92 #endif 93 94 // Check the strong exception guarantee during reallocation failures 95 void test_allocation_exceptions() { 96 // 97 // Tests for std::length_error during reallocation failures 98 // 99 { 100 std::vector<int> v; 101 test_allocation_exception_for_strong_guarantee(v, std::vector<int>(), v.max_size() + 1); 102 } 103 check_new_delete_called(); 104 105 { 106 int a[] = {1, 2, 3, 4, 5}; 107 std::vector<int> in(a, a + sizeof(a) / sizeof(a[0])); 108 std::vector<int> v(in.begin(), in.end()); 109 test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1); 110 } 111 check_new_delete_called(); 112 113 { 114 int a[] = {1, 2, 3, 4, 5}; 115 std::vector<int> in(a, a + sizeof(a) / sizeof(a[0])); 116 std::vector<int, min_allocator<int> > v(in.begin(), in.end()); 117 test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1); 118 } 119 check_new_delete_called(); 120 121 { 122 int a[] = {1, 2, 3, 4, 5}; 123 std::vector<int> in(a, a + sizeof(a) / sizeof(a[0])); 124 std::vector<int, safe_allocator<int> > v(in.begin(), in.end()); 125 test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1); 126 } 127 check_new_delete_called(); 128 129 { 130 int a[] = {1, 2, 3, 4, 5}; 131 std::vector<int> in(a, a + sizeof(a) / sizeof(a[0])); 132 std::vector<int, test_allocator<int> > v(in.begin(), in.end()); 133 test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1); 134 } 135 check_new_delete_called(); 136 137 { 138 std::vector<int> in(10, 42); 139 std::vector<int, limited_allocator<int, 100> > v(in.begin(), in.end()); 140 test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1); 141 } 142 check_new_delete_called(); 143 144 #if TEST_STD_VER >= 23 145 { 146 std::vector<int> in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 147 std::vector<int, increasing_allocator<int>> v(in.begin(), in.end()); 148 test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1); 149 } 150 check_new_delete_called(); 151 #endif 152 153 // 154 // Tests for std::bad_alloc during reallocation failures 155 // 156 { 157 std::vector<int> in(10, 42); 158 std::vector<int, limited_allocator<int, 100> > v(in.begin(), in.end()); 159 test_allocation_exception_for_strong_guarantee(v, in, 91); 160 } 161 check_new_delete_called(); 162 163 { 164 std::vector<int> in(10, 42); 165 std::vector<int, limited_allocator<int, 100> > v(in.begin(), in.end()); 166 v.reserve(30); 167 test_allocation_exception_for_strong_guarantee(v, in, 61); 168 } 169 check_new_delete_called(); 170 171 #if TEST_STD_VER >= 11 172 { 173 std::vector<MoveOnly> in(10); 174 std::vector<MoveOnly, limited_allocator<MoveOnly, 100> > v(10); 175 test_allocation_exception_for_strong_guarantee(v, in, 91); 176 } 177 check_new_delete_called(); 178 179 { 180 std::vector<MoveOnly> in(10); 181 in.insert(in.cbegin() + 5, MoveOnly(42)); 182 std::vector<MoveOnly, limited_allocator<MoveOnly, 100> > v(10); 183 v.reserve(30); 184 v.insert(v.cbegin() + 5, MoveOnly(42)); 185 test_allocation_exception_for_strong_guarantee(v, in, 61); 186 } 187 check_new_delete_called(); 188 #endif 189 190 { // Practical example: Testing with 100 integers. 191 auto in = getIntegerInputs(100); 192 std::vector<int, limited_allocator<int, 299> > v(in.begin(), in.end()); 193 test_allocation_exception_for_strong_guarantee(v, in, 200); 194 } 195 check_new_delete_called(); 196 197 { // Practical example: Testing with 100 strings, each 256 characters long. 198 std::vector<std::string> in = getStringInputsWithLength(100, 256); 199 std::vector<std::string, limited_allocator<std::string, 299> > v(in.begin(), in.end()); 200 test_allocation_exception_for_strong_guarantee(v, in, 200); 201 } 202 check_new_delete_called(); 203 } 204 205 // Check the strong exception guarantee during copy-constructor failures 206 void test_copy_ctor_exceptions() { 207 { 208 int a[] = {1, 2, 3, 4, 5}; 209 std::vector<int> in(a, a + sizeof(a) / sizeof(a[0])); 210 std::vector<throwing_data<int> > v; 211 test_copy_ctor_exception_for_strong_guarantee(v, in); 212 } 213 check_new_delete_called(); 214 215 { 216 int a[] = {1, 2, 3, 4, 5}; 217 std::vector<int> in(a, a + sizeof(a) / sizeof(a[0])); 218 std::vector<throwing_data<int>, min_allocator<throwing_data<int> > > v; 219 test_copy_ctor_exception_for_strong_guarantee(v, in); 220 } 221 check_new_delete_called(); 222 223 { 224 std::vector<int> in(10, 42); 225 std::vector<throwing_data<int>, safe_allocator<throwing_data<int> > > v; 226 test_copy_ctor_exception_for_strong_guarantee(v, in); 227 } 228 check_new_delete_called(); 229 230 { 231 std::vector<int> in(10, 42); 232 std::vector<throwing_data<int>, test_allocator<throwing_data<int> > > v; 233 test_copy_ctor_exception_for_strong_guarantee(v, in); 234 } 235 check_new_delete_called(); 236 237 { 238 std::vector<int> in(10, 42); 239 std::vector<throwing_data<int>, limited_allocator<throwing_data<int>, 100> > v; 240 test_copy_ctor_exception_for_strong_guarantee(v, in); 241 } 242 check_new_delete_called(); 243 244 #if TEST_STD_VER >= 23 245 { 246 std::vector<int> in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 247 std::vector<throwing_data<int>, increasing_allocator<throwing_data<int>>> v; 248 test_copy_ctor_exception_for_strong_guarantee(v, in); 249 } 250 check_new_delete_called(); 251 #endif 252 253 { // Practical example: Testing with 100 integers. 254 auto in = getIntegerInputs(100); 255 std::vector<throwing_data<int> > v; 256 test_copy_ctor_exception_for_strong_guarantee(v, in); 257 } 258 check_new_delete_called(); 259 260 { // Practical example: Testing with 100 strings, each 256 characters long. 261 std::vector<std::string> in = getStringInputsWithLength(100, 256); 262 std::vector<throwing_data<std::string> > v; 263 test_copy_ctor_exception_for_strong_guarantee(v, in); 264 } 265 check_new_delete_called(); 266 } 267 268 #if TEST_STD_VER >= 11 269 270 // Check that if T is Cpp17MoveInsertible && !Cpp17CopyInsertible, and T's move-ctor is not noexcept, then 271 // std::vector::reserve only provides basic guarantee. 272 void test_move_ctor_exceptions() { 273 { 274 std::vector<int> in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 275 std::vector<move_only_throwing_t<int>> v; 276 test_move_ctor_exception_for_basic_guarantee(v, in); 277 } 278 check_new_delete_called(); 279 280 # if TEST_STD_VER >= 23 281 { 282 std::vector<int> in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 283 std::vector<move_only_throwing_t<int>, increasing_allocator<move_only_throwing_t<int>>> v; 284 test_move_ctor_exception_for_basic_guarantee(v, in); 285 } 286 check_new_delete_called(); 287 # endif 288 289 { 290 // Practical example: Testing with 100 strings, each 256 characters long. 291 std::vector<std::string> in = getStringInputsWithLength(100, 256); 292 std::vector<move_only_throwing_t<std::string> > v; 293 test_move_ctor_exception_for_basic_guarantee(v, in); 294 } 295 check_new_delete_called(); 296 } 297 298 #endif 299 300 int main(int, char**) { 301 test_allocation_exceptions(); 302 test_copy_ctor_exceptions(); 303 #if TEST_STD_VER >= 11 304 test_move_ctor_exceptions(); 305 #endif 306 } 307