我有一個純粹的抽象接口類和一個實現該接口的派生類。使用受保護的非虛擬析構函數時,禁止刪除非虛擬dtor警告
struct Foo
{
virtual void doStuff() = 0;
};
struct Bar : Foo
{
void doStuff() override { }
};
我的接口類沒有虛析構函數。
試圖使用一個基類指針破壞派生實例明顯,因此不確定的行爲
int main()
{
Foo* f = new Bar;
f->doStuff();
delete f;
}
幸運的是我的編譯器是聰明地抓住這個(與-Werror
)
main.cc:15:9: error: deleting object of abstract class type ‘Foo’ which has non-virtual destructor will cause undefined behaviour [-Werror=delete-non-virtual-dtor] delete f; ^
我可以通過確保我不試圖使用基類指針來刪除這個未定義的行爲
int main()
{
Bar* b = new Bar;
b->doStuff();
delete b;
}
可惜這不是足夠聰明,拿起這個程序是良好的,並吐出了一個類似的錯誤
main.cc:15:9: error: deleting object of polymorphic class type ‘Bar’ which has non-virtual destructor might cause undefined behaviour [-Werror=delete-non-virtual-dtor] delete b; ^
有趣的是,它說威力導致不確定的行爲,而不是將
受保護的非虛擬析構函數:
在one of Herb Sutter's Guru of the Week's,他給出了以下建議:
方針#4:基類的析構函數應該是公開和虛擬,或保護和非虛。
因此,讓我的析構函數保護nonvirtual。
struct Foo
{
virtual void doStuff() = 0;
protected:
~Foo() = default;
};
struct Bar : Foo
{
void doStuff() override { }
};
現在,當我不小心嘗試使用基類指針刪除我得到另一個失敗
int main()
{
Foo* f = new Bar;
f->doStuff();
delete f;
}
main.cc:5:2: error: ‘Foo::~Foo()’ is protected ~Foo() = default; ^ main.cc:17:9: error: within this context delete f; ^
大,這給了我什麼,我一直在尋找。讓我們來修復代碼,所以我不刪除使用一個基類指針
int main()
{
Bar* b = new Bar;
b->doStuff();
delete b;
}
不幸的是我得到了相同的錯誤之前
main.cc:17:9: error: deleting object of polymorphic class type ‘Bar’ which has non-virtual destructor might cause undefined behaviour [-Werror=delete-non-virtual-dtor] delete b; ^
問:
如何我可以獲得兩全其美嗎?
- 保持
delete-non-virtual-dtor
錯誤時,我忘記了建立一個保護非虛析構函數,我試圖通過一個基類指針 - 當我使用保護非虛析構函數禁止警告刪除和我通過一個派生類指針
超級真棒獎金額外刪除:
- 禁止的警告時,我忘了使用保護非虛析構函數,但我通過派生類指針正確刪除
你能把'Bar'標記爲'final class'嗎? – Jarod42
警告似乎是與編譯器相關的。您可能希望將編譯器標籤添加到帖子中。 –
@ Jarod42我可以爲我的層次中的一些類,但不幸的是不是所有的 –