I ran into a surprising revelation when implementing the pimpl idiom with a home made pointer class (I know: why roll your own? But bear with me). The following three files contain a minimal example:
Pointer.h:
#pragma once
template <typename T>
class Pointer
{
public:
Pointer(T*p=0)
: _p(p)
{
}
virtual ~Pointer()
{
delete _p;
}
private:
void operator=(const Pointer&);
Pointer(const Pointer&);
private:
T*_p;
};
Foo.h:
#pragma once
#include "Pointer.h"
struct Foo
{
Foo();
~Foo();
private:
void operator=(const Foo&);
Foo(const Foo&);
private:
Pointer<struct FooPrivate> p;
};
main.cpp:
#include "Foo.h"
int main(int argc, char* argv[])
{
Foo foo;
return 0;
}
Never mind what the innards of Foo.cpp look like. When I compile main.cpp with MSVC 2008, I get the warning:
pointer.h(13) : warning C4150: deletion of pointer to incomplete type 'FooPrivate'; no destructor called
The warning can be avoided by removing the keyword virtual from Pointers destructor.
This makes no sense to me. Is this warning legit, or is it a bug in the MSVC compiler? If so, can I safely ignore the warning?
I know it makes no sense in this case to make the destructor virtual, but remember, this is just a minimal compilable example. My original code is a lot more complex.
Without
virtual, there is only one place the destructor is going to be called; within~Foo, at which point you have presumably fully definedFooPrivate. If another instance ofPointer<FooPrivate>is created elsewhere, you might get the warning back, but since you don’t the compiler can tell you’re behaving safely.With
virtual, you can theoretically derive fromPointer<FooPrivate>, and that new object could be destroyed from somewhere thatFooPrivateisn’t fully defined. The compiler isn’t positive you don’t do this, so it issues a warning. You can safely ignore it in this trivial case, but if you have an actual need for a virtual destructor it might be a good idea to take it to heart.