【问题标题】:Behaviour of delete on novtable base class without a virtual destructor没有虚拟析构函数的 novtable 基类上的删除行为
【发布时间】:2020-11-26 05:39:42
【问题描述】:

据我了解,如果您在接口指针(或更具体地说是基类指针,指向派生类实例)上调用 delete,并且该声明没有虚拟析构函数,则结果行为是未定义的,并且派生对象的析构函数不会被调用。

class ITestInterface
{
  public:
    virtual void DoStuff() = 0;
}

class Test : public ITestInterface
{
  public:
     ~Test(){};

     virtual void DoStuff() {};
}

...

ITestInferface *pThing = new Test();
delete *pThing; // undefined

通常,您要么为基类定义一个虚拟析构函数,要么将其声明为私有以防止在接口指针上调用 delete。

如果你声明的接口没有 vtable

class __declspec(novtable) ITestInterface
{
  public:
    virtual void DoStuff() = 0;
}

现在通过接口指针删除一个对象是明确定义的行为,并调用适当的析构函数吗?我不明白为什么会这样,但有人告诉过我。

【问题讨论】:

    标签: c++ visual-c++ declspec


    【解决方案1】:

    __declspec(novtable)的作用是在类的构造函数和析构函数中省略了vtable指针的初始化。由于纯虚拟接口的 vtable 无论如何都是无用的,因此这是一种减少代码大小的技术。它只会影响构造函数中虚函数的可用性,所以只要您不在构造函数中进行需要虚拟调度的调用(无论如何都是bad idea),一切都很好。

    然而,这个属性并没有说明它在没有声明时会神奇地调用基类型析构函数 virtual。仅根据文档,如果没有显式声明(或继承)的虚拟析构函数,通过指向接口的指针删除对象仍然是未定义的行为。

    【讨论】:

    • 只是将其声明为 novtable 并不能“解决”在删除时无法分派到派生类的析构函数的问题,不是吗?如果接口没有虚析构函数,通过接口指针删除不会查找派生类的析构函数。
    • @Kindread 我显然没有正确处理这部分问题。让我编辑。
    • 谢谢!我是否应该以某种方式澄清我的问题,以使您遇到问题的部分对未来的读者更清楚?
    • @Kindread 不,你的问题完全没问题。我在阅读问题时分心了,没有抓住非虚拟析构函数的重要细节,而是专注于 novtable 部分。
    猜你喜欢
    • 1970-01-01
    • 2014-10-29
    • 2020-12-27
    • 2012-10-11
    • 2012-04-13
    • 2018-06-29
    • 2012-06-26
    • 2016-03-14
    • 2012-04-18
    相关资源
    最近更新 更多