In a freestanding context (no standard libraries, e.g. in operating system development) using g++ the following phenomenon occurs:
class Base {
public:
virtual ~Base() {}
};
class Derived : public Base {
public:
~Derived() {}
};
int main() {
Derived d;
}
When linking it states something like this: undefined reference to operator delete(void*)
Which clearly means that g++ is generating calls to delete operator even though there are zero dynamic memory allocations. This doesn't happen if destructor isn't virtual.
I suspect this has to do with the generated vtable for the class but I'm not entirely sure. Why does this happen?
If I must not declare a delete operator due to the lack of dynamic memory allocation routines, is there a work around?
EDIT1:
To successfully reproduce the problem in g++ 5.1 I used:
g++ -ffreestanding -nostdlib foo.cpp
The delete operator removes a given property from an object. On successful deletion, it will return true , else false will be returned.
When delete is used to deallocate memory for a C++ class object, the object's destructor is called before the object's memory is deallocated (if the object has a destructor). If the operand to the delete operator is a modifiable l-value, its value is undefined after the object is deleted.
Virtual destructors in C++ are used to avoid memory leaks especially when your class contains unmanaged code, i.e., contains pointers or object handles to files, databases or other external objects.
The answer is yes. Destructor for each object is called. On a related note, you should try to avoid using delete whenever possible.
Because of deleting destructors. That are functions that are actually called when you call delete obj
on an object with virtual destructors. It calls the complete object destructor (which chains base object destructors — the ones that you actually define) and then calls operator delete
. This is so that in all places where delete obj
is used, only one call needs to be emitted, and is also used to call operator delete
with the same pointer that was returned from operator new
as required by ISO C++ (although this could be done more costly via dynamic_cast
as well).
It's part of the Itanium ABI that GCC uses.
I don't think you can disable this.
In C++20 there is now a fix: P0722R3. The static void operator delete(T*, std::destroying_delete_t)
deallocation function. It essentially maps to the destroying destructor.
You can just make it not call ::operator delete
, like:
class Base {
public:
void operator delete(Base* p, std::destroying_delete_t) {
// Shouldn't ever call this function
std::terminate(); // Or whatever abort-like function you have on your platform
// The default implemenation without any overrides basically looks like:
// p->~Base(); ::operator delete(p);
// Which is why the call to `operator delete` is generated
}
virtual ~Base() {}
};
class Derived : public Base {
public:
// Calls Base::operator delete in deleting destructor, so no changes needed
~Derived() {}
};
int main() {
Derived d;
}
The deleting destructor is the one called when you do delete ptr_to_obj;
. It can only be called by delete
expressions, so if you have none in your code, this should be fine. If you do, you can replace them with ::delete ptr_to_obj;
and the deleting destructor will no longer be called (it's purpose is to call overriden operator delete
's for classes, and ::delete
will only call the global ::operator delete
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With