[英]Can a templated Pointer class have a virtual destructor?
在使用自制指針 class 實現 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;
};
富.h:
#pragma once
#include "Pointer.h"
struct Foo
{
Foo();
~Foo();
private:
void operator=(const Foo&);
Foo(const Foo&);
private:
Pointer<struct FooPrivate> p;
};
主.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
可以通過從 Pointers 析構函數中刪除關鍵字 virtual 來避免警告。
這對我來說毫無意義。 這個警告是合法的,還是 MSVC 編譯器中的錯誤? 如果是這樣,我可以安全地忽略警告嗎?
我知道在這種情況下將析構函數設為虛擬是沒有意義的,但請記住,這只是一個最小的可編譯示例。 我的原始代碼要復雜得多。
沒有virtual
,只有一個地方會調用析構函數; 在~Foo
中,此時您可能已經完全定義FooPrivate
。 如果在其他地方創建了另一個Pointer<FooPrivate>
實例,您可能會收到警告,但由於您不這樣做,編譯器可以告訴您行為安全。
使用virtual
,理論上您可以從Pointer<FooPrivate>
派生,並且新的 object 可以從FooPrivate
未完全定義的某個地方被銷毀。 編譯器不肯定你不這樣做,所以它會發出警告。 在這種微不足道的情況下,您可以放心地忽略它,但如果您確實需要虛擬析構函數,那么將它牢記在心可能是個好主意。
由於您正在為 class Foo
提供析構函數,因此警告似乎完全不正確和虛假。
只是為了檢查我是否在文件 [foo.cpp] 中添加了此代碼:
#include "foo.h"
#include <iostream>
using namespace std;
struct FooPrivate
{
FooPrivate() { cout << "FooPrivate::<init>" << endl; }
~FooPrivate() { cout << "FooPrivate::<destroy>" << endl; }
};
Foo::Foo()
: p( new FooPrivate )
{
cout << "Foo::<init>" << endl;
}
Foo::~Foo()
{
cout << "Foo::<destroy>" << endl;
}
這產生了與您得到的相同的警告(使用 Visual C++ 10.0),但是 output
FooPrivate::<初始化>
Foo::<初始化>
Foo::<銷毀>
FooPrivate::<銷毀>
顯然,可執行文件並沒有像愚蠢的警告所說的那樣......
干杯&hth.,
在不競爭的類型上調用delete
是未定義的行為。
因為您沒有給出FooPrivate
的完整定義,所以編譯器不知道它的 vtable 是什么樣的。 由於它無法調用它無法定位的虛擬 function,它保釋了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.