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// <memory>
10
11// template<class Y, class D, class A> shared_ptr(Y* p, D d, A a);
12
13#include <memory>
14#include <cassert>
15#include "test_macros.h"
16#include "deleter_types.h"
17#include "test_allocator.h"
18#include "min_allocator.h"
19
20struct A
21{
22 static int count;
23
24 A() {++count;}
25 A(const A&) {++count;}
26 ~A() {--count;}
27};
28
29int A::count = 0;
30
31struct bad_ty { };
32
33struct bad_deleter
34{
35 void operator()(bad_ty) { }
36};
37
38struct no_move_deleter
39{
40 no_move_deleter(no_move_deleter const&) = delete;
41 no_move_deleter(no_move_deleter &&) = delete;
42 void operator()(int*) { }
43};
44
45static_assert(!std::is_move_constructible<no_move_deleter>::value, "");
46
47struct Base { };
48struct Derived : Base { };
49
50template<class T>
51class MoveDeleter
52{
53 MoveDeleter();
54 MoveDeleter(MoveDeleter const&);
55public:
56 MoveDeleter(MoveDeleter&&) {}
57
58 explicit MoveDeleter(int) {}
59
60 void operator()(T* ptr) { delete ptr; }
61};
62
63// https://llvm.org/PR60258
64// Invalid constructor SFINAE for std::shared_ptr's array ctors
65static_assert( std::is_constructible<std::shared_ptr<int>, int*, test_deleter<int>, test_allocator<int> >::value, "");
66static_assert(!std::is_constructible<std::shared_ptr<int>, int*, bad_deleter, test_allocator<int> >::value, "");
67static_assert( std::is_constructible<std::shared_ptr<Base>, Derived*, test_deleter<Base>, test_allocator<Base> >::value, "");
68static_assert(!std::is_constructible<std::shared_ptr<A>, int*, test_deleter<A>, test_allocator<A> >::value, "");
69
70#if TEST_STD_VER >= 17
71static_assert( std::is_constructible<std::shared_ptr<int[]>, int*, test_deleter<int>, test_allocator<int>>::value, "");
72static_assert(!std::is_constructible<std::shared_ptr<int[]>, int*, bad_deleter, test_allocator<int>>::value, "");
73static_assert(!std::is_constructible<std::shared_ptr<int[]>, int(*)[], test_deleter<int>, test_allocator<int>>::value, "");
74static_assert( std::is_constructible<std::shared_ptr<int[5]>, int*, test_deleter<int>, test_allocator<int>>::value, "");
75static_assert(!std::is_constructible<std::shared_ptr<int[5]>, int*, bad_deleter, test_allocator<int>>::value, "");
76static_assert(!std::is_constructible<std::shared_ptr<int[5]>, int(*)[5], test_deleter<int>, test_allocator<int>>::value, "");
77#endif
78
79
80int main(int, char**)
81{
82 {
83 test_allocator_statistics alloc_stats;
84 {
85 A* ptr = new A;
86 std::shared_ptr<A> p(ptr, test_deleter<A>(3), test_allocator<A>(5, &alloc_stats));
87 assert(A::count == 1);
88 assert(p.use_count() == 1);
89 assert(p.get() == ptr);
90 assert(test_deleter<A>::count == 1);
91 assert(test_deleter<A>::dealloc_count == 0);
92#ifndef TEST_HAS_NO_RTTI
93 test_deleter<A>* d = std::get_deleter<test_deleter<A> >(p);
94 assert(d);
95 assert(d->state() == 3);
96#endif
97 assert(alloc_stats.count == 1);
98 assert(alloc_stats.alloc_count == 1);
99 }
100 assert(A::count == 0);
101 assert(test_deleter<A>::count == 0);
102 assert(test_deleter<A>::dealloc_count == 1);
103 assert(alloc_stats.count == 0);
104 assert(alloc_stats.alloc_count == 0);
105 test_deleter<A>::dealloc_count = 0;
106 }
107
108 {
109 test_allocator_statistics alloc_stats;
110 {
111 A const* ptr = new A;
112 std::shared_ptr<A const> p(ptr, test_deleter<A const>(3), test_allocator<A>(5, &alloc_stats));
113 assert(A::count == 1);
114 assert(p.use_count() == 1);
115 assert(p.get() == ptr);
116 assert(test_deleter<A const>::count == 1);
117 assert(test_deleter<A const>::dealloc_count == 0);
118#ifndef TEST_HAS_NO_RTTI
119 test_deleter<A const>* d = std::get_deleter<test_deleter<A const> >(p);
120 assert(d);
121 assert(d->state() == 3);
122#endif
123 assert(alloc_stats.count == 1);
124 assert(alloc_stats.alloc_count == 1);
125 }
126 assert(A::count == 0);
127 assert(test_deleter<A const>::count == 0);
128 assert(test_deleter<A const>::dealloc_count == 1);
129 assert(alloc_stats.count == 0);
130 assert(alloc_stats.alloc_count == 0);
131 test_deleter<A const>::dealloc_count = 0;
132 }
133
134 // Test an allocator with a minimal interface
135 {
136 A* ptr = new A;
137 std::shared_ptr<A> p(ptr, test_deleter<A>(3), bare_allocator<void>());
138 assert(A::count == 1);
139 assert(p.use_count() == 1);
140 assert(p.get() == ptr);
141 assert(test_deleter<A>::count == 1);
142 assert(test_deleter<A>::dealloc_count == 0);
143#ifndef TEST_HAS_NO_RTTI
144 test_deleter<A>* d = std::get_deleter<test_deleter<A> >(p);
145 assert(d);
146 assert(d->state() == 3);
147#endif
148 }
149 assert(A::count == 0);
150 assert(test_deleter<A>::count == 0);
151 assert(test_deleter<A>::dealloc_count == 1);
152 test_deleter<A>::dealloc_count = 0;
153
154#if TEST_STD_VER >= 11
155 // Test an allocator that returns class-type pointers
156 {
157 A* ptr = new A;
158 std::shared_ptr<A> p(ptr, test_deleter<A>(3), min_allocator<void>());
159 assert(A::count == 1);
160 assert(p.use_count() == 1);
161 assert(p.get() == ptr);
162 assert(test_deleter<A>::count == 1);
163 assert(test_deleter<A>::dealloc_count == 0);
164#ifndef TEST_HAS_NO_RTTI
165 test_deleter<A>* d = std::get_deleter<test_deleter<A> >(p);
166 assert(d);
167 assert(d->state() == 3);
168#endif
169 }
170 assert(A::count == 0);
171 assert(test_deleter<A>::count == 0);
172 assert(test_deleter<A>::dealloc_count == 1);
173
174 {
175 MoveDeleter<int> d(0);
176 std::shared_ptr<int> p2(new int, std::move(d), std::allocator<int>());
177 std::shared_ptr<int> p3(nullptr, std::move(d), std::allocator<int>());
178 }
179#endif // TEST_STD_VER >= 11
180
181 {
182 // Make sure we can't construct with:
183 // a) a deleter that doesn't have an operator ()(int*)
184 // b) a deleter that doesn't have a move constructor.
185 static_assert(!std::is_constructible<std::shared_ptr<int>, int*, bad_deleter,
186 test_allocator<A> >::value, "");
187 static_assert(!std::is_constructible<std::shared_ptr<int>, int*, no_move_deleter,
188 test_allocator<A> >::value, "");
189
190 // Make sure that we can construct a shared_ptr where the element type and pointer type
191 // aren't "convertible" but are "compatible".
192 static_assert(!std::is_constructible<std::shared_ptr<Derived[4]>,
193 Base[4], test_deleter<Derived[4]>,
194 test_allocator<Derived[4]> >::value, "");
195 }
196
197 return 0;
198}
199

source code of libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp