I would like to understand why unique_ptr
destructors require the type to be complete upon destruction while that isn't the case with shared_ptr
. This blog from Howard Hinnant briefly mentions it has to do with static vs. dynamic deleters. I'm looking for a more detailed explanation of why that might be the case (it may be compiler implementation specific in which case an example would be helpful). With dynamic deleters, does it restrict the destructor from being inlined?
CodePudding user response:
Howard Hinnant was simplifying. What he precisely meant was if you use the default deleter for std::unique_ptr
, you need a complete type. For the default deleter, it simply calls delete
for you.
The gist of static and dynamic deleters is
class A;
void static_delete(A* p)
{
delete(p);
}
void (*dynamic_delete)(A*) = /* somehow */;
int main()
{
A* p = /* somehow */;
static_delete(p); // undefined behaviour
dynamic_delete(p); // maybe not
}
As long asdynamic_delete
points to a function that's defined where A
is also defined, you have well-defined behaviour.
To prevent undefined behaviour, the default deleter checks for a complete type, which may be implemented as
void default_delete(A* p)
{
static_assert(sizeof(A) > 0);
delete(p);
}
CodePudding user response:
I would like to understand why
unique_ptr
destructors require the type to be complete upon destruction while that isn't the case withshared_ptr
I believe that is as simple as that default destructor needs to know the size of data members. For unique_ptr
the deleter is part of the object representation, whilst for shared_ptr
the actual deleter is not that relevant, because it's stored in the control block, no matter what kind of deleter you use