1 //===----------------------------------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is dual licensed under the MIT and the University of Illinois Open 6 // Source Licenses. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // <memory> 11 12 // unique_ptr 13 14 //============================================================================= 15 // TESTING unique_ptr(pointer, deleter) 16 // 17 // Concerns: 18 // 1 unique_ptr(pointer, deleter&&) only requires a MoveConstructible deleter. 19 // 2 unique_ptr(pointer, deleter&) requires a CopyConstructible deleter. 20 // 3 unique_ptr<T, D&>(pointer, deleter) does not require a CopyConstructible deleter. 21 // 4 unique_ptr<T, D const&>(pointer, deleter) does not require a CopyConstructible deleter. 22 // 5 unique_ptr(pointer, deleter) should work for derived pointers. 23 // 6 unique_ptr(pointer, deleter) should work with function pointers. 24 // 7 unique_ptr<void> should work. 25 26 #include <memory> 27 #include <cassert> 28 29 #include "test_macros.h" 30 #include "unique_ptr_test_helper.h" 31 32 bool my_free_called = false; 33 34 void my_free(void*) { my_free_called = true; } 35 36 #if TEST_STD_VER >= 11 37 struct DeleterBase { 38 void operator()(void*) const {} 39 }; 40 struct CopyOnlyDeleter : DeleterBase { 41 CopyOnlyDeleter() = default; 42 CopyOnlyDeleter(CopyOnlyDeleter const&) = default; 43 CopyOnlyDeleter(CopyOnlyDeleter&&) = delete; 44 }; 45 struct MoveOnlyDeleter : DeleterBase { 46 MoveOnlyDeleter() = default; 47 MoveOnlyDeleter(MoveOnlyDeleter&&) = default; 48 }; 49 struct NoCopyMoveDeleter : DeleterBase { 50 NoCopyMoveDeleter() = default; 51 NoCopyMoveDeleter(NoCopyMoveDeleter const&) = delete; 52 }; 53 #endif 54 55 template <bool IsArray> 56 void test_sfinae() { 57 #if TEST_STD_VER >= 11 58 typedef typename std::conditional<!IsArray, int, int[]>::type VT; 59 { 60 using D = CopyOnlyDeleter; 61 using U = std::unique_ptr<VT, D>; 62 static_assert(std::is_constructible<U, int*, D const&>::value, ""); 63 static_assert(std::is_constructible<U, int*, D&>::value, ""); 64 static_assert(std::is_constructible<U, int*, D&&>::value, ""); 65 // FIXME: __libcpp_compressed_pair attempts to perform a move even though 66 // it should only copy. 67 //D d; 68 //U u(nullptr, std::move(d)); 69 } 70 { 71 using D = MoveOnlyDeleter; 72 using U = std::unique_ptr<VT, D>; 73 static_assert(!std::is_constructible<U, int*, D const&>::value, ""); 74 static_assert(!std::is_constructible<U, int*, D&>::value, ""); 75 static_assert(std::is_constructible<U, int*, D&&>::value, ""); 76 D d; 77 U u(nullptr, std::move(d)); 78 } 79 { 80 using D = NoCopyMoveDeleter; 81 using U = std::unique_ptr<VT, D>; 82 static_assert(!std::is_constructible<U, int*, D const&>::value, ""); 83 static_assert(!std::is_constructible<U, int*, D&>::value, ""); 84 static_assert(!std::is_constructible<U, int*, D&&>::value, ""); 85 } 86 { 87 using D = NoCopyMoveDeleter; 88 using U = std::unique_ptr<VT, D&>; 89 static_assert(!std::is_constructible<U, int*, D const&>::value, ""); 90 static_assert(std::is_constructible<U, int*, D&>::value, ""); 91 static_assert(!std::is_constructible<U, int*, D&&>::value, ""); 92 static_assert(!std::is_constructible<U, int*, const D&&>::value, ""); 93 } 94 { 95 using D = NoCopyMoveDeleter; 96 using U = std::unique_ptr<VT, const D&>; 97 static_assert(std::is_constructible<U, int*, D const&>::value, ""); 98 static_assert(std::is_constructible<U, int*, D&>::value, ""); 99 static_assert(!std::is_constructible<U, int*, D&&>::value, ""); 100 static_assert(!std::is_constructible<U, int*, const D&&>::value, ""); 101 } 102 #endif 103 } 104 105 template <bool IsArray> 106 void test_noexcept() { 107 #if TEST_STD_VER >= 11 108 typedef typename std::conditional<!IsArray, int, int[]>::type VT; 109 { 110 using D = CopyOnlyDeleter; 111 using U = std::unique_ptr<VT, D>; 112 static_assert(std::is_nothrow_constructible<U, int*, D const&>::value, ""); 113 static_assert(std::is_nothrow_constructible<U, int*, D&>::value, ""); 114 static_assert(std::is_nothrow_constructible<U, int*, D&&>::value, ""); 115 } 116 { 117 using D = MoveOnlyDeleter; 118 using U = std::unique_ptr<VT, D>; 119 static_assert(std::is_nothrow_constructible<U, int*, D&&>::value, ""); 120 D d; 121 U u(nullptr, std::move(d)); 122 } 123 { 124 using D = NoCopyMoveDeleter; 125 using U = std::unique_ptr<VT, D&>; 126 static_assert(std::is_nothrow_constructible<U, int*, D&>::value, ""); 127 } 128 { 129 using D = NoCopyMoveDeleter; 130 using U = std::unique_ptr<VT, const D&>; 131 static_assert(std::is_nothrow_constructible<U, int*, D const&>::value, ""); 132 static_assert(std::is_nothrow_constructible<U, int*, D&>::value, ""); 133 } 134 #endif 135 } 136 137 void test_sfinae_runtime() { 138 #if TEST_STD_VER >= 11 139 { 140 using D = CopyOnlyDeleter; 141 using U = std::unique_ptr<A[], D>; 142 static_assert(std::is_nothrow_constructible<U, A*, D const&>::value, ""); 143 static_assert(std::is_nothrow_constructible<U, A*, D&>::value, ""); 144 static_assert(std::is_nothrow_constructible<U, A*, D&&>::value, ""); 145 146 static_assert(!std::is_constructible<U, B*, D const&>::value, ""); 147 static_assert(!std::is_constructible<U, B*, D&>::value, ""); 148 static_assert(!std::is_constructible<U, B*, D&&>::value, ""); 149 // FIXME: __libcpp_compressed_pair attempts to perform a move even though 150 // it should only copy. 151 //D d; 152 //U u(nullptr, std::move(d)); 153 } 154 { 155 using D = MoveOnlyDeleter; 156 using U = std::unique_ptr<A[], D>; 157 static_assert(!std::is_constructible<U, A*, D const&>::value, ""); 158 static_assert(!std::is_constructible<U, A*, D&>::value, ""); 159 static_assert(std::is_nothrow_constructible<U, A*, D&&>::value, ""); 160 161 static_assert(!std::is_constructible<U, B*, D const&>::value, ""); 162 static_assert(!std::is_constructible<U, B*, D&>::value, ""); 163 static_assert(!std::is_constructible<U, B*, D&&>::value, ""); 164 D d; 165 U u(nullptr, std::move(d)); 166 } 167 { 168 using D = NoCopyMoveDeleter; 169 using U = std::unique_ptr<A[], D>; 170 static_assert(!std::is_constructible<U, A*, D const&>::value, ""); 171 static_assert(!std::is_constructible<U, A*, D&>::value, ""); 172 static_assert(!std::is_constructible<U, A*, D&&>::value, ""); 173 174 static_assert(!std::is_constructible<U, B*, D const&>::value, ""); 175 static_assert(!std::is_constructible<U, B*, D&>::value, ""); 176 static_assert(!std::is_constructible<U, B*, D&&>::value, ""); 177 } 178 { 179 using D = NoCopyMoveDeleter; 180 using U = std::unique_ptr<A[], D&>; 181 static_assert(!std::is_constructible<U, A*, D const&>::value, ""); 182 static_assert(std::is_nothrow_constructible<U, A*, D&>::value, ""); 183 static_assert(!std::is_constructible<U, A*, D&&>::value, ""); 184 static_assert(!std::is_constructible<U, A*, const D&&>::value, ""); 185 186 static_assert(!std::is_constructible<U, B*, D const&>::value, ""); 187 static_assert(!std::is_constructible<U, B*, D&>::value, ""); 188 static_assert(!std::is_constructible<U, B*, D&&>::value, ""); 189 static_assert(!std::is_constructible<U, B*, const D&&>::value, ""); 190 } 191 { 192 using D = NoCopyMoveDeleter; 193 using U = std::unique_ptr<A[], const D&>; 194 static_assert(std::is_nothrow_constructible<U, A*, D const&>::value, ""); 195 static_assert(std::is_nothrow_constructible<U, A*, D&>::value, ""); 196 static_assert(!std::is_constructible<U, A*, D&&>::value, ""); 197 static_assert(!std::is_constructible<U, A*, const D&&>::value, ""); 198 199 static_assert(!std::is_constructible<U, B*, D const&>::value, ""); 200 static_assert(!std::is_constructible<U, B*, D&>::value, ""); 201 static_assert(!std::is_constructible<U, B*, D&&>::value, ""); 202 static_assert(!std::is_constructible<U, B*, const D&&>::value, ""); 203 } 204 #endif 205 } 206 207 template <bool IsArray> 208 void test_basic() { 209 typedef typename std::conditional<!IsArray, A, A[]>::type VT; 210 const int expect_alive = IsArray ? 5 : 1; 211 { // MoveConstructible deleter (C-1) 212 A* p = newValue<VT>(expect_alive); 213 assert(A::count == expect_alive); 214 std::unique_ptr<VT, Deleter<VT> > s(p, Deleter<VT>(5)); 215 assert(s.get() == p); 216 assert(s.get_deleter().state() == 5); 217 } 218 assert(A::count == 0); 219 { // CopyConstructible deleter (C-2) 220 A* p = newValue<VT>(expect_alive); 221 assert(A::count == expect_alive); 222 CopyDeleter<VT> d(5); 223 std::unique_ptr<VT, CopyDeleter<VT> > s(p, d); 224 assert(s.get() == p); 225 assert(s.get_deleter().state() == 5); 226 d.set_state(6); 227 assert(s.get_deleter().state() == 5); 228 } 229 assert(A::count == 0); 230 { // Reference deleter (C-3) 231 A* p = newValue<VT>(expect_alive); 232 assert(A::count == expect_alive); 233 NCDeleter<VT> d(5); 234 std::unique_ptr<VT, NCDeleter<VT>&> s(p, d); 235 assert(s.get() == p); 236 assert(&s.get_deleter() == &d); 237 assert(s.get_deleter().state() == 5); 238 d.set_state(6); 239 assert(s.get_deleter().state() == 6); 240 } 241 assert(A::count == 0); 242 { // Const Reference deleter (C-4) 243 A* p = newValue<VT>(expect_alive); 244 assert(A::count == expect_alive); 245 NCConstDeleter<VT> d(5); 246 std::unique_ptr<VT, NCConstDeleter<VT> const&> s(p, d); 247 assert(s.get() == p); 248 assert(s.get_deleter().state() == 5); 249 assert(&s.get_deleter() == &d); 250 } 251 assert(A::count == 0); 252 { // Void and function pointers (C-6,7) 253 typedef typename std::conditional<IsArray, int[], int>::type VT2; 254 my_free_called = false; 255 { 256 int i = 0; 257 std::unique_ptr<VT2, void (*)(void*)> s(&i, my_free); 258 assert(s.get() == &i); 259 assert(s.get_deleter() == my_free); 260 assert(!my_free_called); 261 } 262 assert(my_free_called); 263 } 264 } 265 266 void test_basic_single() { 267 assert(A::count == 0); 268 assert(B::count == 0); 269 { // Derived pointers (C-5) 270 B* p = new B; 271 assert(A::count == 1); 272 assert(B::count == 1); 273 std::unique_ptr<A, Deleter<A> > s(p, Deleter<A>(5)); 274 assert(s.get() == p); 275 assert(s.get_deleter().state() == 5); 276 } 277 assert(A::count == 0); 278 assert(B::count == 0); 279 { // Void and function pointers (C-6,7) 280 my_free_called = false; 281 { 282 int i = 0; 283 std::unique_ptr<void, void (*)(void*)> s(&i, my_free); 284 assert(s.get() == &i); 285 assert(s.get_deleter() == my_free); 286 assert(!my_free_called); 287 } 288 assert(my_free_called); 289 } 290 } 291 292 template <bool IsArray> 293 void test_nullptr() { 294 #if TEST_STD_VER >= 11 295 typedef typename std::conditional<!IsArray, A, A[]>::type VT; 296 { 297 std::unique_ptr<VT, Deleter<VT> > u(nullptr, Deleter<VT>{}); 298 assert(u.get() == nullptr); 299 } 300 { 301 NCDeleter<VT> d; 302 std::unique_ptr<VT, NCDeleter<VT>& > u(nullptr, d); 303 assert(u.get() == nullptr); 304 } 305 { 306 NCConstDeleter<VT> d; 307 std::unique_ptr<VT, NCConstDeleter<VT> const& > u(nullptr, d); 308 assert(u.get() == nullptr); 309 } 310 #endif 311 } 312 313 int main() { 314 { 315 test_basic</*IsArray*/ false>(); 316 test_nullptr<false>(); 317 test_basic_single(); 318 test_sfinae<false>(); 319 test_noexcept<false>(); 320 } 321 { 322 test_basic</*IsArray*/ true>(); 323 test_nullptr<true>(); 324 test_sfinae<true>(); 325 test_sfinae_runtime(); 326 test_noexcept<true>(); 327 } 328 } 329