我有一个纯粹的抽象接口类和一个实现该接口的派生类。使用受保护的非虚拟析构函数时,禁止删除非虚拟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我可以为我的层次中的一些类,但不幸的是不是所有的 –