为什么虚拟析构函数会写入内存?
Why does a virtual destructor write to memory?
最近,在使用自定义分配器代码和放置 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;
}
直播link:https://godbolt.org/z/jWv6qs3Wc
这是输出:
Initial first byte: 0xff
After ctor, first byte: 0x68
After destroy, first byte: 0x88
如果我删除虚拟 Interface
,那么内存就不会像预期的那样发生任何变化。
这是某种调试功能吗?
这似乎是特定于编译器的。 Clang 不会,但是 GCC 会。
-O2
似乎确实消失了。但是,我仍然不确定它的目的。
为了销毁一个 Derived
,概念上调用 Derived::~Derived
(在这种情况下什么都不做),然后调整 vtable 以便对象是一个 Interface
,然后 Interface::~Interface
被调用。您正在观察的是指向 Interface
vtable 的指针(如 here 所示,构建 Interface
给出相同的第一个字节)。
如果启用优化,那么由于 Interface::~Interface
什么都不做,Derived::~Derived
也可以优化为无操作,并且您会看到打印的第一个字节相同。
最近,在使用自定义分配器代码和放置 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;
}
直播link:https://godbolt.org/z/jWv6qs3Wc
这是输出:
Initial first byte: 0xff
After ctor, first byte: 0x68
After destroy, first byte: 0x88
如果我删除虚拟 Interface
,那么内存就不会像预期的那样发生任何变化。
这是某种调试功能吗?
这似乎是特定于编译器的。 Clang 不会,但是 GCC 会。
-O2
似乎确实消失了。但是,我仍然不确定它的目的。
为了销毁一个 Derived
,概念上调用 Derived::~Derived
(在这种情况下什么都不做),然后调整 vtable 以便对象是一个 Interface
,然后 Interface::~Interface
被调用。您正在观察的是指向 Interface
vtable 的指针(如 here 所示,构建 Interface
给出相同的第一个字节)。
如果启用优化,那么由于 Interface::~Interface
什么都不做,Derived::~Derived
也可以优化为无操作,并且您会看到打印的第一个字节相同。