When implementing my own unique_ptr
( just for fun), I found it cannot pass this test file from libstdcxx
:
struct A;
struct B
{
std::unique_ptr<A> a;
};
struct A
{
B* b;
~A() { VERIFY(b->a != nullptr); }
};
void test01()
{
B b;
b.a.reset(new A);
b.a->b = &b;
}
gcc passes this test file happily (of course, this file is from libstdcxx), while clang fails for the VERIFY
part.
Question:
b->a != nullptr
) is important for gcc, otherwise it'll not have a test file for it, but I don't know what's behind it. Is it related to optimization? I know many UB are for better optimizations.clang
(libc++) seems to be non-compliant on this point because the standard says:
~unique_ptr();
Requires: The expression
get_deleter()(get())
shall be well-formed, shall have well-defined behavior, and shall not throw exceptions. [ Note: The use ofdefault_delete
requiresT
to be a complete type. — end note ]Effects: If
get() == nullptr
there are no effects. Otherwiseget_deleter()(get())
.
So the destructor should be equivalent to get_deleter()(get())
, which would imply that b->a
cannot be nullptr
within the destructor of A
(which is called inside get_deleter()
by the delete
instruction).
On a side note, both clang
(libc++) and gcc
(libstdc++) sets the pointer to nullptr
when destroying a std::unique_ptr
, but here is gcc
destructor:
auto& __ptr = _M_t._M_ptr();
if (__ptr != nullptr)
get_deleter()(__ptr);
__ptr = pointer();
...and here is clang
(call to reset()
):
pointer __tmp = __ptr_.first();
__ptr_.first() = pointer();
if (__tmp)
__ptr_.second()(__tmp);
As you can see, gcc
first deletes then assigns to nullptr
(pointer()
) while clang
first assigns to nullptr
(pointer()
) then delete1.
1 pointer
is an alias corresponding to Deleter::pointer
, if it exists, or simply T*
.