为什么虚拟析构函数需要删除运算符

时间:2015-07-28 20:32:23

标签: c++ delete-operator virtual-destructor

在使用g ++的独立上下文(没有标准库,例如在操作系统开发中)中,会出现以下现象:

class Base {
public:
   virtual ~Base() {}
};

class Derived : public Base {
public:
    ~Derived() {}
};

int main() {
    Derived d;
}

链接时,请说明以下内容:undefined reference to operator delete(void*)

这显然意味着即使动态内存分配为零,g ++也会生成删除运算符的调用。如果析构函数不是虚拟的,那么这不会发生。

我怀疑这与课堂生成的vtable有关,但我并不完全确定。 为什么会这样?

如果由于缺少动态内存分配例程而不能声明删除操作符,是否有解决方法?

EDIT1:

为了成功地重现我使用的g ++ 5.1中的问题:

g ++ -ffreestanding -nostdlib foo.cpp

2 个答案:

答案 0 :(得分:13)

因为删除了析构函数。这是在使用虚拟析构函数的对象上调用delete obj时实际调用的函数。它调用完整的对象析构函数(它链接基础对象析构函数 - 您实际定义的那些),然后调用operator delete。这样,在使用delete obj的所有地方,只需要发出一个调用,并且还用于使用operator delete根据需要返回的相同指针调用operator new通过ISO C ++(虽然这可以通过dynamic_cast来实现更高成本。)

它是GCC使用的Itanium ABI的一部分。

我认为你不能禁用它。

答案 1 :(得分:0)

在C ++ 20中,现在有一个修复程序:P0722R3static void operator delete(T*, std::destroying_delete_t)释放功能。它本质上映射到销毁的析构函数。

您可以使其不调用::operator delete,例如:

class Base {
public:
    void operator delete(Base* p, std::destroying_delete_t) {
        // Shouldn't ever call this function
        std::terminate();  // Or whatever abort-like function you have on your platform

        // The default implemenation without any overrides basically looks like:
        // p->~Base(); ::operator delete(p);
        // Which is why the call to `operator delete` is generated
    }
    virtual ~Base() {}
};

class Derived : public Base {
public:
    // Calls Base::operator delete in deleting destructor, so no changes needed
    ~Derived() {}
};

int main() {
    Derived d;
}

删除析构函数是您执行delete ptr_to_obj;时所调用的析构函数。它只能由delete表达式调用,因此,如果代码中没有表达式,则可以。如果这样做,则可以用::delete ptr_to_obj;替换它们,删除的析构函数将不再被调用(其目的是为类调用重写的operator delete,而::delete仅调用全局::operator delete