最近,在编写自定义分配器代码和放置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
如果我移除虚拟Interface
,那么内存就不会改变,这是预期的行为。
这是一种调试功能吗?
它似乎是编译器特定的。Clang 不会这样做,但是 GCC 会。
使用-O2
选项似乎可以解决此问题。但是,我仍然不确定它的目的。
new
导致字符数组中的字符的生命周期结束)。 - M.MDerived
。 - M.Malignas
的问题;我已经修复了它(行为相同)。我同意这是未定义的行为,因为它写得很模糊;我真的想要理解实际发生的事情的具体细节,而不仅仅是标准所说的。我会在问题中澄清这一点。我想知道:如果它是来自malloc
的void*
,那么它是否仍然是未定义的行为?毕竟,free
在之后访问该内存是被允许的。 - jwd