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
30template <typename T, typename Alloc>
31void 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
49template <typename T, typename Alloc>
50void 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
76template <typename T, typename Alloc>
77void 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
95void 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, values: std::vector<int>(), new_cap: 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, values: in, new_cap: 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(n: 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(n: 100, len: 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
206void 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, values: 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(n: 100);
255 std::vector<throwing_data<int> > v;
256 test_copy_ctor_exception_for_strong_guarantee(v, values: 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(n: 100, len: 256);
262 std::vector<throwing_data<std::string> > v;
263 test_copy_ctor_exception_for_strong_guarantee(v, values: 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.
272void 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
300int 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

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of libcxx/test/std/containers/sequences/vector/vector.capacity/reserve_exceptions.pass.cpp