当用自制的指针类实现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;
};
Run Code Online (Sandbox Code Playgroud)
foo.h中:
#pragma once
#include "Pointer.h"
struct Foo
{
Foo();
~Foo();
private:
void operator=(const Foo&);
Foo(const Foo&);
private:
Pointer<struct FooPrivate> p;
};
Run Code Online (Sandbox Code Playgroud)
main.cpp中:
#include "Foo.h"
int main(int argc, char* argv[])
{
Foo foo;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
别介意内脏的Foo.cpp
样子.当我main.cpp
使用MSVC 2008 编译时,我收到警告:
pointer.h(13) : warning C4150: deletion of pointer to incomplete type 'FooPrivate'; no destructor called
Run Code Online (Sandbox Code Playgroud)
通过从Pointers析构函数中删除关键字virtual可以避免警告.
这对我来说毫无意义.这个警告是合法的,还是MSVC编译器中的错误?如果是这样,我可以安全地忽略警告吗?
我知道在这种情况下使析构函数虚拟是没有意义的,但请记住,这只是一个最小的可编译示例.我原来的代码要复杂得多.
如果没有virtual
,则只有一处将调用析构函数;在 之内~Foo
,此时您大概已经完全定义了FooPrivate
。如果在其他地方创建了另一个实例Pointer<FooPrivate>
,您可能会收到警告,但由于您没有这样做,编译器可以告诉您的行为是安全的。
使用virtual
,理论上您可以从 派生Pointer<FooPrivate>
,并且可以从未完全定义的地方销毁该新对象FooPrivate
。编译器不确定您不这样做,因此会发出警告。在这种微不足道的情况下,您可以放心地忽略它,但如果您确实需要虚拟析构函数,那么认真考虑它可能是个好主意。
归档时间: |
|
查看次数: |
2460 次 |
最近记录: |