简体   繁体   English

为什么虚拟析构函数会写入 memory?

[英]Why does a virtual destructor write to memory?

Recently, when working with custom allocator code and placement new+delete, I noticed something that surprised me: When a virtual destructor is called, it writes to the object's soon-to-be-freed memory.最近,在使用自定义分配器代码和放置 new+delete 时,我注意到一些令我惊讶的事情:当调用虚拟析构函数时,它会写入对象即将释放的 memory。

Why is that?这是为什么?

(update) Aside: I'm more interested in the actual behavior here, not what the C++ standard has to say, which I'm sure does not specify this behavior. (更新)除此之外:我对这里的实际行为更感兴趣,而不是 C++ 标准必须说的,我确信没有指定这种行为。

Here's a small program to demonstrate:这是一个小程序来演示:

#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;
}

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

Here is the output:这是 output:

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

If I remove the virtual Interface , then the memory never changes at all, as expected.如果我删除 virtual Interface ,那么 memory 正如预期的那样根本不会改变。

Is this some kind of debug functionality?这是某种调试功能吗?

It seems compiler-specific.它似乎是特定于编译器的。 Clang does not do it, but GCC does. Clang 不这样做,但 GCC 可以。

It does seem to go away with -O2 .似乎 go 离开-O2 But still, I'm not sure it's purpose.但是,我仍然不确定它的目的。

To destroy a Derived , conceptually Derived::~Derived is called (which does nothing in this case), then the vtable is adjusted so that the object is an Interface , then Interface::~Interface is called.要销毁Derived ,在概念上调用Derived::~Derived (在这种情况下不执行任何操作),然后调整 vtable 以使 object 是一个Interface ,然后调用Interface::~Interface What you are observing is the pointer to the Interface vtable (as seen here , constructing an Interface gives the same first byte).您正在观察的是指向Interface vtable 的指针(如此处所示,构造Interface给出相同的第一个字节)。

If you enable optimisations, then since Interface::~Interface does nothing, Derived::~Derived can be optimised to a no-op too, and you see the same first byte printed.如果启用优化,那么由于Interface::~Interface什么都不做, Derived::~Derived也可以优化为无操作,并且您会看到打印的第一个字节相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM