是否有某种方法可以检测是否使用非虚拟基析构函数错误地删除了类



众所周知的场景:

#include <memory>
class A{};
class B : public A {};
int main()
{
    std::unique_ptr<A> a = std::make_unique<B>();
    // bam, when a gets deleted, we have undefined behavior.
    return 0; 
}

此外,如果AB的大小相同,即使是Valgrind也无法捕捉到这样的错误。

有没有一些工具可以捕捉到这样的错误,至少在调试构建中是这样,或者有没有一些习惯用法可以检测指定类的这样的错误?

对于gcc,您可以指定:

-Wdelete-non-virtual-dtor -Wsystem-headers

要查看delete-non-virtual-dtor警告生成的by std::default_delete,它将如下所示:

/usr/local/include/c++/5.3.0/bits/unique_ptr.h:76:2:警告:删除具有非虚拟析构函数的多态类类型"B"的对象可能会导致未定义的行为[-Wdelete非虚拟dtor]删除__ptr;

实时

顺便说一句。您的示例类在基类中至少缺少一个虚拟函数。

[编辑]

将其转化为错误使用:

 -Werror=delete-non-virtual-dtor -Wsystem-headers 

我强烈认为应该严格区分"基于值"的类和"基于OO"的类(因为没有更好的术语)。

基于值的类不应该有公共基,并且通常应该支持复制语义(除非专门设计为禁用复制)。这些类的对象除了其值之外没有任何身份。它们可以与复制品互换。

基于OO的类应该具有虚拟析构函数,并且不应该具有可公开访问的复制成员。此类对象只能通过虚拟clone方法进行复制。这些对象具有与其值分离的身份。

不应该有任何具有公共基的类具有非虚拟析构函数、公共复制/移动构造函数或公共复制/移赋值运算符(在基中)。

如果保持这种分离,那么通过非多态基指针进行对象切片或删除就不会发生意外。

不幸的是,(据我所知)没有任何工具可以帮助保持这种分离。因此,您需要在继承时尽职调查。这真的很简单。它是否有一个虚拟dtor不可访问/已删除的副本ctor和副本分配?你可以公开继承。不避免潜在的混乱,使用组合或私有继承。

为继承而设计的好类会保护其复制成员,以便在子类中进行克隆。

不幸的是,对于第三方类,您别无选择,因为作者通常会将复制成员公开,因此仍然存在对象切片的风险。但是,您将不会有通过基指针进行不当删除的风险。

TL;DR没有工具,只有程序员的尽职调查。

相关内容

最新更新