//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // unique_ptr //============================================================================= // TESTING unique_ptr(pointer, deleter) // // Concerns: // 1 unique_ptr(pointer, deleter&&) only requires a MoveConstructible deleter. // 2 unique_ptr(pointer, deleter&) requires a CopyConstructible deleter. // 3 unique_ptr(pointer, deleter) does not require a CopyConstructible deleter. // 4 unique_ptr(pointer, deleter) does not require a CopyConstructible deleter. // 5 unique_ptr(pointer, deleter) should work for derived pointers. // 6 unique_ptr(pointer, deleter) should work with function pointers. // 7 unique_ptr should work. #include #include #include "test_macros.h" #include "unique_ptr_test_helper.h" bool my_free_called = false; void my_free(void*) { my_free_called = true; } #if TEST_STD_VER >= 11 struct DeleterBase { void operator()(void*) const {} }; struct CopyOnlyDeleter : DeleterBase { CopyOnlyDeleter() = default; CopyOnlyDeleter(CopyOnlyDeleter const&) = default; CopyOnlyDeleter(CopyOnlyDeleter&&) = delete; }; struct MoveOnlyDeleter : DeleterBase { MoveOnlyDeleter() = default; MoveOnlyDeleter(MoveOnlyDeleter&&) = default; }; struct NoCopyMoveDeleter : DeleterBase { NoCopyMoveDeleter() = default; NoCopyMoveDeleter(NoCopyMoveDeleter const&) = delete; }; #endif template void test_sfinae() { #if TEST_STD_VER >= 11 typedef typename std::conditional::type VT; { using D = CopyOnlyDeleter; using U = std::unique_ptr; static_assert(std::is_constructible::value, ""); static_assert(std::is_constructible::value, ""); static_assert(std::is_constructible::value, ""); // FIXME: __libcpp_compressed_pair attempts to perform a move even though // it should only copy. //D d; //U u(nullptr, std::move(d)); } { using D = MoveOnlyDeleter; using U = std::unique_ptr; static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(std::is_constructible::value, ""); D d; U u(nullptr, std::move(d)); } { using D = NoCopyMoveDeleter; using U = std::unique_ptr; static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); } { using D = NoCopyMoveDeleter; using U = std::unique_ptr; static_assert(!std::is_constructible::value, ""); static_assert(std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); } { using D = NoCopyMoveDeleter; using U = std::unique_ptr; static_assert(std::is_constructible::value, ""); static_assert(std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); } #endif } template void test_noexcept() { #if TEST_STD_VER >= 11 typedef typename std::conditional::type VT; { using D = CopyOnlyDeleter; using U = std::unique_ptr; static_assert(std::is_nothrow_constructible::value, ""); static_assert(std::is_nothrow_constructible::value, ""); static_assert(std::is_nothrow_constructible::value, ""); } { using D = MoveOnlyDeleter; using U = std::unique_ptr; static_assert(std::is_nothrow_constructible::value, ""); D d; U u(nullptr, std::move(d)); } { using D = NoCopyMoveDeleter; using U = std::unique_ptr; static_assert(std::is_nothrow_constructible::value, ""); } { using D = NoCopyMoveDeleter; using U = std::unique_ptr; static_assert(std::is_nothrow_constructible::value, ""); static_assert(std::is_nothrow_constructible::value, ""); } #endif } void test_sfinae_runtime() { #if TEST_STD_VER >= 11 { using D = CopyOnlyDeleter; using U = std::unique_ptr; static_assert(std::is_nothrow_constructible::value, ""); static_assert(std::is_nothrow_constructible::value, ""); static_assert(std::is_nothrow_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); // FIXME: __libcpp_compressed_pair attempts to perform a move even though // it should only copy. //D d; //U u(nullptr, std::move(d)); } { using D = MoveOnlyDeleter; using U = std::unique_ptr; static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(std::is_nothrow_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); D d; U u(nullptr, std::move(d)); } { using D = NoCopyMoveDeleter; using U = std::unique_ptr; static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); } { using D = NoCopyMoveDeleter; using U = std::unique_ptr; static_assert(!std::is_constructible::value, ""); static_assert(std::is_nothrow_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); } { using D = NoCopyMoveDeleter; using U = std::unique_ptr; static_assert(std::is_nothrow_constructible::value, ""); static_assert(std::is_nothrow_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); } #endif } template void test_basic() { typedef typename std::conditional::type VT; const int expect_alive = IsArray ? 5 : 1; { // MoveConstructible deleter (C-1) A* p = newValue(expect_alive); assert(A::count == expect_alive); std::unique_ptr > s(p, Deleter(5)); assert(s.get() == p); assert(s.get_deleter().state() == 5); } assert(A::count == 0); { // CopyConstructible deleter (C-2) A* p = newValue(expect_alive); assert(A::count == expect_alive); CopyDeleter d(5); std::unique_ptr > s(p, d); assert(s.get() == p); assert(s.get_deleter().state() == 5); d.set_state(6); assert(s.get_deleter().state() == 5); } assert(A::count == 0); { // Reference deleter (C-3) A* p = newValue(expect_alive); assert(A::count == expect_alive); NCDeleter d(5); std::unique_ptr&> s(p, d); assert(s.get() == p); assert(&s.get_deleter() == &d); assert(s.get_deleter().state() == 5); d.set_state(6); assert(s.get_deleter().state() == 6); } assert(A::count == 0); { // Const Reference deleter (C-4) A* p = newValue(expect_alive); assert(A::count == expect_alive); NCConstDeleter d(5); std::unique_ptr const&> s(p, d); assert(s.get() == p); assert(s.get_deleter().state() == 5); assert(&s.get_deleter() == &d); } assert(A::count == 0); { // Void and function pointers (C-6,7) typedef typename std::conditional::type VT2; my_free_called = false; { int i = 0; std::unique_ptr s(&i, my_free); assert(s.get() == &i); assert(s.get_deleter() == my_free); assert(!my_free_called); } assert(my_free_called); } } void test_basic_single() { assert(A::count == 0); assert(B::count == 0); { // Derived pointers (C-5) B* p = new B; assert(A::count == 1); assert(B::count == 1); std::unique_ptr > s(p, Deleter(5)); assert(s.get() == p); assert(s.get_deleter().state() == 5); } assert(A::count == 0); assert(B::count == 0); { // Void and function pointers (C-6,7) my_free_called = false; { int i = 0; std::unique_ptr s(&i, my_free); assert(s.get() == &i); assert(s.get_deleter() == my_free); assert(!my_free_called); } assert(my_free_called); } } template void test_nullptr() { #if TEST_STD_VER >= 11 typedef typename std::conditional::type VT; { std::unique_ptr > u(nullptr, Deleter{}); assert(u.get() == nullptr); } { NCDeleter d; std::unique_ptr& > u(nullptr, d); assert(u.get() == nullptr); } { NCConstDeleter d; std::unique_ptr const& > u(nullptr, d); assert(u.get() == nullptr); } #endif } int main(int, char**) { { test_basic(); test_nullptr(); test_basic_single(); test_sfinae(); test_noexcept(); } { test_basic(); test_nullptr(); test_sfinae(); test_sfinae_runtime(); test_noexcept(); } return 0; }