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.Nullability - a scoped_ptr or unique_ptr can be null, a value object can never be. Polymorphism - a value object is always exactly its static type, but you can substitute in different derived types for a unique_ptr. The previously-held object is automatically destroyed when you do this.
Yes. Well the unique ptr has a function object that by default invokes delete on the pointed to object, which calls the destructor. You can change the type of that default deleter to do almost anything.
unique_ptr allows only one owner of the underlying pointer while shared_ptr is a reference-counted smart pointer. In this implementation, the developer doesn't need to explicitly delete the allocated memory towards the end of the function.
std::unique_ptr::getReturns the stored pointer. The stored pointer points to the object managed by the unique_ptr, if any, or to nullptr if the unique_ptr is empty.
clang
(libc++) seems to be non-compliant on this point because the standard says:
[unique.ptr.single.dtor]
~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.
1pointer
is an alias corresponding to Deleter::pointer
, if it exists, or simply T*
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With