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: c++03, c++11, c++14, c++17
10
11// <memory>
12
13// shared_ptr
14
15// template<class T>
16// shared_ptr<T> make_shared(); // T is U[N]
17//
18// template<class T>
19// shared_ptr<T> make_shared(const remove_extent_t<T>& u); // T is U[N]
20
21#include <cassert>
22#include <concepts>
23#include <cstdint> // std::uintptr_t
24#include <memory>
25#include <utility>
26
27#include "operator_hijacker.h"
28#include "types.h"
29
30template <class T, class ...Args>
31concept CanMakeShared = requires(Args&& ...args) {
32 { std::make_shared<T>(std::forward<Args>(args)...) } -> std::same_as<std::shared_ptr<T>>;
33};
34
35int main(int, char**) {
36 // Make sure we initialize elements correctly
37 {
38 // Without passing an initial value
39 {
40 using Array = int[8];
41 std::shared_ptr<Array> ptr = std::make_shared<Array>();
42 for (unsigned i = 0; i < 8; ++i) {
43 assert(ptr[i] == 0);
44 }
45 }
46 {
47 using Array = int[8][3];
48 std::shared_ptr<Array> ptr = std::make_shared<Array>();
49 for (unsigned i = 0; i < 8; ++i) {
50 assert(ptr[i][0] == 0);
51 assert(ptr[i][1] == 0);
52 assert(ptr[i][2] == 0);
53 }
54 }
55 {
56 using Array = int[8][3][2];
57 std::shared_ptr<Array> ptr = std::make_shared<Array>();
58 for (unsigned i = 0; i < 8; ++i) {
59 assert(ptr[i][0][0] == 0);
60 assert(ptr[i][0][1] == 0);
61 assert(ptr[i][1][0] == 0);
62 assert(ptr[i][1][1] == 0);
63 assert(ptr[i][2][0] == 0);
64 assert(ptr[i][2][1] == 0);
65 }
66 }
67
68 // Passing an initial value
69 {
70 using Array = int[8];
71 int init = 42;
72 std::shared_ptr<Array> ptr = std::make_shared<Array>(args&: init);
73 for (unsigned i = 0; i < 8; ++i) {
74 assert(ptr[i] == init);
75 }
76 }
77 {
78 using Array = int[8][3];
79 int init[3] = {42, 43, 44};
80 std::shared_ptr<Array> ptr = std::make_shared<Array>(args&: init);
81 for (unsigned i = 0; i < 8; ++i) {
82 assert(ptr[i][0] == 42);
83 assert(ptr[i][1] == 43);
84 assert(ptr[i][2] == 44);
85 }
86 }
87 {
88 using Array = int[8][3][2];
89 int init[3][2] = {{31, 32}, {41, 42}, {51, 52}};
90 std::shared_ptr<Array> ptr = std::make_shared<Array>(args&: init);
91 for (unsigned i = 0; i < 8; ++i) {
92 assert(ptr[i][0][0] == 31);
93 assert(ptr[i][0][1] == 32);
94 assert(ptr[i][1][0] == 41);
95 assert(ptr[i][1][1] == 42);
96 assert(ptr[i][2][0] == 51);
97 assert(ptr[i][2][1] == 52);
98 }
99 }
100 }
101
102 // Make sure array elements are destroyed in reverse order
103 {
104 // Without passing an initial value
105 {
106 using Array = DestroyInReverseOrder[8];
107 DestroyInReverseOrder::reset();
108 {
109 std::shared_ptr<Array> ptr = std::make_shared<Array>();
110 assert(DestroyInReverseOrder::alive() == 8);
111 }
112 assert(DestroyInReverseOrder::alive() == 0);
113 }
114 {
115 using Array = DestroyInReverseOrder[8][3];
116 DestroyInReverseOrder::reset();
117 {
118 std::shared_ptr<Array> ptr = std::make_shared<Array>();
119 assert(DestroyInReverseOrder::alive() == 8 * 3);
120 }
121 assert(DestroyInReverseOrder::alive() == 0);
122 }
123 {
124 using Array = DestroyInReverseOrder[8][3][2];
125 DestroyInReverseOrder::reset();
126 {
127 std::shared_ptr<Array> ptr = std::make_shared<Array>();
128 assert(DestroyInReverseOrder::alive() == 8 * 3 * 2);
129 }
130 assert(DestroyInReverseOrder::alive() == 0);
131 }
132
133 // Passing an initial value
134 {
135 using Array = DestroyInReverseOrder[8];
136 int count = 0;
137 DestroyInReverseOrder init(&count);
138 int init_count = 1;
139 {
140 std::shared_ptr<Array> ptr = std::make_shared<Array>(args&: init);
141 assert(count == 8 + init_count);
142 }
143 assert(count == init_count);
144 }
145 {
146 using Array = DestroyInReverseOrder[8][3];
147 int count = 0;
148 DestroyInReverseOrder init[3] = {&count, &count, &count};
149 int init_count = 3;
150 {
151 std::shared_ptr<Array> ptr = std::make_shared<Array>(args&: init);
152 assert(count == 8 * 3 + init_count);
153 }
154 assert(count == init_count);
155 }
156 {
157 using Array = DestroyInReverseOrder[8][3][2];
158 int count = 0;
159 DestroyInReverseOrder init[3][2] = {{&count, &count}, {&count, &count}, {&count, &count}};
160 int init_count = 3 * 2;
161 {
162 std::shared_ptr<Array> ptr = std::make_shared<Array>(args&: init);
163 assert(count == 8 * 3 * 2 + init_count);
164 }
165 assert(count == init_count);
166 }
167 }
168
169 // Count the number of copies being made
170 {
171 // Without passing an initial value
172 {
173 using Array = CountCopies[8];
174 CountCopies::reset();
175 std::shared_ptr<Array> ptr = std::make_shared<Array>();
176 assert(CountCopies::copies() == 0);
177 }
178 {
179 using Array = CountCopies[8][3];
180 CountCopies::reset();
181 std::shared_ptr<Array> ptr = std::make_shared<Array>();
182 assert(CountCopies::copies() == 0);
183 }
184 {
185 using Array = CountCopies[8][3][2];
186 CountCopies::reset();
187 std::shared_ptr<Array> ptr = std::make_shared<Array>();
188 assert(CountCopies::copies() == 0);
189 }
190
191 // Passing an initial value
192 {
193 using Array = CountCopies[8];
194 int copies = 0;
195 CountCopies init(&copies);
196 std::shared_ptr<Array> ptr = std::make_shared<Array>(args&: init);
197 assert(copies == 8);
198 }
199 {
200 using Array = CountCopies[8][3];
201 int copies = 0;
202 CountCopies init[3] = {&copies, &copies, &copies};
203 std::shared_ptr<Array> ptr = std::make_shared<Array>(args&: init);
204 assert(copies == 8 * 3);
205 }
206 {
207 using Array = CountCopies[8][3][2];
208 int copies = 0;
209 CountCopies init[3][2] = {{&copies, &copies}, {&copies, &copies}, {&copies, &copies}};
210 std::shared_ptr<Array> ptr = std::make_shared<Array>(args&: init);
211 assert(copies == 8 * 3 * 2);
212 }
213 }
214
215 // Make sure array elements are aligned properly when the array contains an overaligned type.
216 //
217 // Here, we don't need to test both the with-initial-value and without-initial-value code paths,
218 // since we're just checking the alignment and both are going to use the same code path unless
219 // the implementation is completely crazy.
220 {
221 auto check_alignment = []<class T> {
222 {
223 using Array = T[8];
224 std::shared_ptr ptr = std::make_shared<Array>();
225 for (int i = 0; i < 8; ++i) {
226 T* p = std::addressof(ptr[i]);
227 assert(reinterpret_cast<std::uintptr_t>(p) % alignof(T) == 0);
228 }
229 }
230 {
231 using Array = T[8][3];
232 std::shared_ptr ptr = std::make_shared<Array>();
233 for (int i = 0; i < 8; ++i) {
234 for (int j = 0; j < 3; ++j) {
235 T* p = std::addressof(ptr[i][j]);
236 assert(reinterpret_cast<std::uintptr_t>(p) % alignof(T) == 0);
237 }
238 }
239 }
240 {
241 using Array = T[8][3][2];
242 std::shared_ptr ptr = std::make_shared<Array>();
243 for (int i = 0; i < 8; ++i) {
244 for (int j = 0; j < 3; ++j) {
245 for (int k = 0; k < 2; ++k) {
246 T* p = std::addressof(ptr[i][j][k]);
247 assert(reinterpret_cast<std::uintptr_t>(p) % alignof(T) == 0);
248 }
249 }
250 }
251 }
252 };
253
254 struct Empty { };
255 check_alignment.operator()<Empty>();
256 check_alignment.operator()<OverAligned>();
257 check_alignment.operator()<MaxAligned>();
258
259 // test non corner cases as well while we're at it
260 struct Foo { int i; char c; };
261 check_alignment.operator()<int>();
262 check_alignment.operator()<Foo>();
263 }
264
265 // Make sure that we destroy all the elements constructed so far when an exception
266 // is thrown. Also make sure that we do it in reverse order of construction.
267#ifndef TEST_HAS_NO_EXCEPTIONS
268 {
269 struct Sentinel : ThrowOnConstruction, DestroyInReverseOrder { };
270
271 // Without passing an initial value
272 {
273 using Array = Sentinel[8];
274 for (int i = 0; i < 8; ++i) {
275 ThrowOnConstruction::throw_after(n: i);
276 DestroyInReverseOrder::reset();
277 try {
278 std::shared_ptr<Array> ptr = std::make_shared<Array>();
279 assert(false);
280 } catch (ThrowOnConstruction::exception const&) {
281 assert(DestroyInReverseOrder::alive() == 0);
282 }
283 }
284 }
285 {
286 using Array = Sentinel[8][3];
287 for (int i = 0; i < 8 * 3; ++i) {
288 ThrowOnConstruction::throw_after(n: i);
289 DestroyInReverseOrder::reset();
290 try {
291 std::shared_ptr<Array> ptr = std::make_shared<Array>();
292 assert(false);
293 } catch (ThrowOnConstruction::exception const&) {
294 assert(DestroyInReverseOrder::alive() == 0);
295 }
296 }
297 }
298 {
299 using Array = Sentinel[8][3][2];
300 for (int i = 0; i < 8 * 3 * 2; ++i) {
301 ThrowOnConstruction::throw_after(n: i);
302 DestroyInReverseOrder::reset();
303 try {
304 std::shared_ptr<Array> ptr = std::make_shared<Array>();
305 assert(false);
306 } catch (ThrowOnConstruction::exception const&) {
307 assert(DestroyInReverseOrder::alive() == 0);
308 }
309 }
310 }
311
312 // Passing an initial value
313 {
314 using Array = Sentinel[8];
315 for (int i = 0; i < 8; ++i) {
316 DestroyInReverseOrder::reset();
317 ThrowOnConstruction::reset();
318 Sentinel init;
319 ThrowOnConstruction::throw_after(n: i);
320 try {
321 std::shared_ptr<Array> ptr = std::make_shared<Array>(args&: init);
322 assert(false);
323 } catch (ThrowOnConstruction::exception const&) {
324 assert(DestroyInReverseOrder::alive() == 1);
325 }
326 }
327 }
328 {
329 using Array = Sentinel[8][3];
330 for (int i = 0; i < 8 * 3; ++i) {
331 DestroyInReverseOrder::reset();
332 ThrowOnConstruction::reset();
333 Sentinel init[3] = {};
334 ThrowOnConstruction::throw_after(n: i);
335 try {
336 std::shared_ptr<Array> ptr = std::make_shared<Array>(args&: init);
337 assert(false);
338 } catch (ThrowOnConstruction::exception const&) {
339 assert(DestroyInReverseOrder::alive() == 3);
340 }
341 }
342 }
343 {
344 using Array = Sentinel[8][3][2];
345 for (int i = 0; i < 8 * 3 * 2; ++i) {
346 DestroyInReverseOrder::reset();
347 ThrowOnConstruction::reset();
348 Sentinel init[3][2] = {};
349 ThrowOnConstruction::throw_after(n: i);
350 try {
351 std::shared_ptr<Array> ptr = std::make_shared<Array>(args&: init);
352 assert(false);
353 } catch (ThrowOnConstruction::exception const&) {
354 assert(DestroyInReverseOrder::alive() == 3 * 2);
355 }
356 }
357 }
358 }
359#endif // TEST_HAS_NO_EXCEPTIONS
360
361 // Make sure the version without an initialization argument works even for non-movable types
362 {
363 using Array = NonMovable[8][3];
364 std::shared_ptr<Array> ptr = std::make_shared<Array>();
365 (void)ptr;
366 }
367
368 // Make sure std::make_shared handles badly-behaved types properly
369 {
370 using Array = operator_hijacker[3];
371 std::shared_ptr<Array> p1 = std::make_shared<Array>();
372 std::shared_ptr<Array> p2 = std::make_shared<Array>(operator_hijacker());
373 assert(p1 != nullptr);
374 assert(p2 != nullptr);
375 }
376
377 // Check that we SFINAE-away for invalid arguments
378 {
379 struct T { };
380 static_assert( CanMakeShared<T[8]>);
381 static_assert( CanMakeShared<T[8], T>);
382 static_assert(!CanMakeShared<T[8], T, int>); // too many arguments
383 }
384
385 return 0;
386}
387

source code of libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared.array.bounded.pass.cpp