//===----------------------------------------------------------------------===// // // 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 // Test unique_ptr converting move ctor // NOTE: unique_ptr does not provide converting constructors in C++03 // UNSUPPORTED: c++98, c++03 #include #include #include #include #include "test_macros.h" #include "unique_ptr_test_helper.h" // test converting move ctor. Should only require a MoveConstructible deleter, or if // deleter is a reference, not even that. // Explicit version template void checkReferenceDeleter(LHS& lhs, RHS& rhs) { typedef typename LHS::deleter_type NewDel; static_assert(std::is_reference::value, ""); rhs.get_deleter().set_state(42); assert(rhs.get_deleter().state() == 42); assert(lhs.get_deleter().state() == 42); lhs.get_deleter().set_state(99); assert(lhs.get_deleter().state() == 99); assert(rhs.get_deleter().state() == 99); } template void checkDeleter(LHS& lhs, RHS& rhs, int LHSVal, int RHSVal) { assert(lhs.get_deleter().state() == LHSVal); assert(rhs.get_deleter().state() == RHSVal); } template void checkCtor(LHS& lhs, RHS& rhs, A* RHSVal) { assert(lhs.get() == RHSVal); assert(rhs.get() == nullptr); assert(A::count == 1); assert(B::count == 1); } void checkNoneAlive() { assert(A::count == 0); assert(B::count == 0); } template struct NCConvertingDeleter { NCConvertingDeleter() = default; NCConvertingDeleter(NCConvertingDeleter const&) = delete; NCConvertingDeleter(NCConvertingDeleter&&) = default; template NCConvertingDeleter(NCConvertingDeleter&&) {} void operator()(T*) const {} }; template struct NCConvertingDeleter { NCConvertingDeleter() = default; NCConvertingDeleter(NCConvertingDeleter const&) = delete; NCConvertingDeleter(NCConvertingDeleter&&) = default; template NCConvertingDeleter(NCConvertingDeleter&&) {} void operator()(T*) const {} }; struct NCGenericDeleter { NCGenericDeleter() = default; NCGenericDeleter(NCGenericDeleter const&) = delete; NCGenericDeleter(NCGenericDeleter&&) = default; void operator()(void*) const {} }; void test_sfinae() { using DA = NCConvertingDeleter; // non-copyable deleters using DB = NCConvertingDeleter; using UA = std::unique_ptr; using UB = std::unique_ptr; using UAD = std::unique_ptr; using UBD = std::unique_ptr; { // cannot move from an lvalue static_assert(std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); } { // cannot move if the deleter-types cannot convert static_assert(std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); } { // cannot move-convert with reference deleters of different types using UA1 = std::unique_ptr; using UB1 = std::unique_ptr; static_assert(!std::is_constructible::value, ""); } { // cannot move-convert with reference deleters of different types using UA1 = std::unique_ptr; using UB1 = std::unique_ptr; static_assert(!std::is_constructible::value, ""); } { // cannot move-convert from unique_ptr using UA1 = std::unique_ptr; using UA2 = std::unique_ptr; using UB1 = std::unique_ptr; static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); } { // cannot move-convert from unique_ptr using UA1 = std::unique_ptr; using UA2 = std::unique_ptr; using UB1 = std::unique_ptr; static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); } } void test_noexcept() { { typedef std::unique_ptr APtr; typedef std::unique_ptr BPtr; static_assert(std::is_nothrow_constructible::value, ""); } { typedef std::unique_ptr > APtr; typedef std::unique_ptr > BPtr; static_assert(std::is_nothrow_constructible::value, ""); } { typedef std::unique_ptr&> APtr; typedef std::unique_ptr&> BPtr; static_assert(std::is_nothrow_constructible::value, ""); } { typedef std::unique_ptr&> APtr; typedef std::unique_ptr&> BPtr; static_assert(std::is_nothrow_constructible::value, ""); } } int main(int, char**) { { test_sfinae(); test_noexcept(); } { typedef std::unique_ptr APtr; typedef std::unique_ptr BPtr; { // explicit BPtr b(new B); A* p = b.get(); APtr a(std::move(b)); checkCtor(a, b, p); } checkNoneAlive(); { // implicit BPtr b(new B); A* p = b.get(); APtr a = std::move(b); checkCtor(a, b, p); } checkNoneAlive(); } { // test with moveable deleters typedef std::unique_ptr > APtr; typedef std::unique_ptr > BPtr; { Deleter del(5); BPtr b(new B, std::move(del)); A* p = b.get(); APtr a(std::move(b)); checkCtor(a, b, p); checkDeleter(a, b, 5, 0); } checkNoneAlive(); { Deleter del(5); BPtr b(new B, std::move(del)); A* p = b.get(); APtr a = std::move(b); checkCtor(a, b, p); checkDeleter(a, b, 5, 0); } checkNoneAlive(); } { // test with reference deleters typedef std::unique_ptr&> APtr; typedef std::unique_ptr&> BPtr; NCDeleter del(5); { BPtr b(new B, del); A* p = b.get(); APtr a(std::move(b)); checkCtor(a, b, p); checkReferenceDeleter(a, b); } checkNoneAlive(); { BPtr b(new B, del); A* p = b.get(); APtr a = std::move(b); checkCtor(a, b, p); checkReferenceDeleter(a, b); } checkNoneAlive(); } { typedef std::unique_ptr > APtr; typedef std::unique_ptr&> BPtr; CDeleter del(5); { BPtr b(new B, del); A* p = b.get(); APtr a(std::move(b)); checkCtor(a, b, p); checkDeleter(a, b, 5, 5); } checkNoneAlive(); { BPtr b(new B, del); A* p = b.get(); APtr a = std::move(b); checkCtor(a, b, p); checkDeleter(a, b, 5, 5); } checkNoneAlive(); } return 0; }