Why is "error: invalid application of 'sizeof' to an incomplete type using unique_ptr" fixed by adding an empty destructor?
Solution 1
If we go to the cppreference document for std::unique_ptr
:
std::unique_ptr
may be constructed for an incomplete typeT
, such as to facilitate the use as a handle in the Pimpl idiom. If the default deleter is used,T
must be complete at the point in code where the deleter is invoked, which happens in the destructor, move assignment operator, and reset member function ofstd::unique_ptr
. (Conversely,std::shared_ptr
can't be constructed from a raw pointer to incomplete type, but can be destroyed whereT
is incomplete).
We can see in the below code:
#include <memory>
class STFT; // pimpl off to prevent point name clash
class Whatever
{
public:
~Whatever() ;
private:
std::unique_ptr<STFT> stft;
} ;
//class STFT{};
Whatever::~Whatever() {}
int main(){}
The requirements are not fulfilled when the defintion of STFT
is commented before the destructor of Whatever
is defined since this requires the destructor for stft
which in turn requires STFT
to be complete.
So it seems likely that in your implementation file STFT
is complete when Whatever::~Whatever()
is defined but otherwise the defaulted one is created without the STFT
being complete.
Solution 2
My usual idiom for providing such destructors is
Whatever::~Whatever() = default;
The important thing is that it needs to be somewhere where the pointed-to type(s) are complete.
Related videos on Youtube
Comments
-
learnvst almost 2 years
I am Pimpling off the class
STFT
. Compiles just fine with this in the header:class STFT; // pimpl off to prevent point name clash class Whatever { private: STFT* stft;
and this in the implementation:
#include "STFT.h" Whatever::Whatever() : stft(new STFT()) { // blah blah } Whatever::~Whatever() { delete stft; // pure evil }
However, switching to
std::unique_ptr<STFT> stft;
over the raw pointer in the header, and removing the destructor, I geterror: invalid application of 'sizeof' to an incomplete type 'STFT' static_assert(sizeof(_Tp) > 0, "default_delete can not delete incomplete type");
But if I simply supply an empty destructor
Whatever::~Whatever(){}
, then it compiles fine. This has me completely stumped. Please fill me in on what this meaningless destructor is doing for me. -
learnvst over 8 yearsUsing that syntax gives same error. I need to explicitly declare an empty dtor.
-
Toby Speight over 8 yearsThat depends where you put it. If you put it in the header, where
STFT
is incomplete, then it's as bad as letting the compiler generate it where it's needed. It needs to be in the implementation file, after#include <stft>
, where all the pointed-to types are complete. If it didn't work, I wouldn't be using it myself. -
learnvst over 8 yearsAhhhh. Ok. That works
-
Nikos C. almost 7 yearsIs there any difference whatsoever compared to
Whatever::~Whatever() {}
? That one is 7 characters shorter :-P -
Toby Speight almost 7 yearsTechnically, there is a different between an explicitly-defaulted destructor and a user-supplied empty destructor, but I can't think of a practical difference right now. I find the explicit
default
faster to read, and damn the expense!