当我使用自制指针类实现pimpl习惯用法时,我遇到了一个令人惊讶的发现(我知道:为什么要自己造轮子呢?但请耐心听我说)。以下三个文件包含了一个最小化的示例:
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;
}
不用关心Foo.cpp
的内部结构。当我使用MSVC 2008编译main.cpp
时,会出现警告:
pointer.h(13) : warning C4150: deletion of pointer to incomplete type 'FooPrivate'; no destructor called
可以通过在指针析构函数中删除关键字virtual来避免此警告。
这对我来说没有任何意义。这个警告是合法的吗?还是MSVC编译器的一个bug?如果是后者,我可以安全地忽略这个警告吗?
我知道在这种情况下使析构函数虚拟化是毫无意义的,但请记住,这只是一个最小可编译示例。我的原始代码要复杂得多。
~Foo()
,还是使用编译器提供的默认析构函数?你无需采取任何措施,一个空的函数体就可以了,只要在编写它之前FooPrivate
在 “Foo.cpp” 中已经完全定义好了。 - Dennis Zickefoose~Foo()
在类定义中声明,因此它是用户定义的(或根本未定义,在这种情况下,稍后应该会出现链接错误)。Foo.cpp
的内容与main.cpp
的编译无关,因为它们是不同的翻译单元,而这是一个编译时而不是链接时的警告。 - Steve JessopFooPrivate
定义之前就可能发生用户自定义析构函数...但由于没有virtual
警告消失了,几乎可以确定这不是问题的原因。 - Dennis Zickefoose