/// Primary template of default_delete, used by unique_ptr
template<typename _Tp>
struct default_delete
{
...
void
operator()(_Tp* __ptr) const
{
static_assert(!is_void<_Tp>::value,
"can't delete pointer to incomplete type");
static_assert(sizeof(_Tp)>0,
"can't delete pointer to incomplete type");
delete __ptr;
}
};
Basically, invoking "operator delete" on a pointer to an incomplete type (aka opaque pointer) is usually undefined. Calling "operator new" on an incomplete type is not possible (because its size is 0). Since unique_ptr deals with allocation/deallocation, and doesn't just copy pointer values around, it's not fully comparable to a plain pointer.nice_byte proposed a good solution: if you can, abstract the new/delete logic to another file, in which the complete type of "Gadget" is known.
The missing puzzle piece is apparently exception handling: if the implicit constructor throws (which of course it cannot) it must delete this object (which of course will be null). Sadly this silly requirement persists even when exception handling is disabled at the compiler level.
Intention is to avoid undefined behaviour in situation where you delete an object with incomplete class type at the point of deletion, that has a non-trivial destructor or a deallocation function.
Edit: An deleter is used because of default generated copy constructor.
The reason it fails to compile is probably that the implicitly generate constructor of BlackBox (which is inline, I guess) may need to call the dtor of unique_ptr in case something in the constructor throws an exception.