为什么虚拟析构函数写入内存?

最近,在使用自定义分配器代码和放置 new+delete 时,我注意到一些令我惊讶的事情:当调用虚拟析构函数时,它会写入对象即将被释放的内存。

这是为什么?

(更新) 旁白:我对这里的实际行为更感兴趣,而不是 C++ 标准所说的,我确信它没有指定这种行为。

这里有一个小程序来演示:

#include <new>
#include <cstring>
#include <iostream>

using std::cout;
using std::endl;

struct Interface {
    virtual ~Interface() = default;
};

struct Derived : public Interface {
};

alignas(Derived) unsigned char buffer[sizeof(Derived)];

int main() {

    memset(buffer, 0xff, sizeof(buffer));
    cout << "Initial first byte: 0x" << std::hex << (int)buffer[0] << endl;
    
    // Create an instance, using 'data' as storage
    Derived *pDer = ::new (buffer) Derived();
    cout << "After ctor, first byte: 0x" << std::hex << (int)buffer[0] << endl;
    
    pDer->~Derived();
    
    cout << "After destroy, first byte: 0x" << std::hex << (int)buffer[0] << endl;

    return 0;
}

直播链接:https : //godbolt.org/z/jWv6qs3Wc

这是输出:

Initial first byte: 0xff
After ctor, first byte: 0x68
After destroy, first byte: 0x88

如果我删除 virtual Interface,那么内存根本不会改变,正如预期的那样。

这是某种调试功能吗?

这似乎是特定于编译器的。Clang 不会这样做,但 GCC 会这样做。

它似乎确实消失了-O2。但是,我仍然不确定它的目的。

回答

要销毁 a Derived,在概念上Derived::~Derived被调用(在这种情况下它什么都不做),然后调整 vtable 以便对象是 an Interface,然后Interface::~Interface被调用。你所观察到的是指向Interface虚函数表(如看到这里,构建一个Interface提供相同的第一个字节)。

如果您启用优化,那么因为Interface::~Interface什么都不做,Derived::~Derived也可以优化为无操作,并且您会看到打印的第一个字节。


以上是为什么虚拟析构函数写入内存?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>