Reputation: 11144
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.
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.
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
Here is the 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.
Is this some kind of debug functionality?
It seems compiler-specific. Clang does not do it, but GCC does.
It does seem to go away with -O2
. But still, I'm not sure it's purpose.
Upvotes: 3
Views: 136
Reputation: 40881
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. What you are observing is the pointer to the Interface
vtable (as seen here, constructing an Interface
gives the same first byte).
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.
Upvotes: 10