【发布时间】:2011-06-28 17:02:51
【问题描述】:
在使用自制指针类实现 pimpl 习语时,我遇到了一个令人惊讶的发现(我知道:为什么要自己动手?但请耐心等待)。以下三个文件包含一个最小示例:
指针.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 编译器中的错误?如果是这样,我可以放心地忽略该警告吗?
我知道在这种情况下将析构函数设为虚拟是没有意义的,但请记住,这只是一个最小的可编译示例。我的原始代码要复杂得多。
【问题讨论】:
-
当您写 bear with me 时,我认为滚动您自己的智能指针的原因将在您的帖子中稍后介绍。可悲的是它不是。所以,我不得不问 - 为什么?
-
您是否查看过 std::auto_ptr (cplusplus.com/reference/std/memory/auto_ptr) 或 Boost Smart 指针 (boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm)?
-
Foo.cpp的内部结构在这里非常重要...您实际上有明确的~Foo(),还是使用提供的编译器?你不需要做任何事情,一个空的 body 就可以了,只要在你写之前FooPrivate已经在Foo.cpp中完全定义好了。 -
@Dennis:
~Foo()在类定义中声明。所以它是用户定义的(或者根本没有定义,在这种情况下,一段时间后应该会导致链接错误)。Foo.cpp的内容与main.cpp的编译无关,因为它们是不同的翻译单元,这是编译时而不是链接时警告。 -
@Steve:我实际上并不是要发布该评论,而是选择创建一个正确的答案。然而,理论上,用户定义的析构函数可能发生在
FooPrivate... 的定义之前,但由于警告在没有virtual的情况下消失,因此几乎可以肯定情况并非如此。
标签: c++ visual-c++