Do Default Destructors Do Anything?

April 2024 ยท 4 minute read

I was wondering if default class destructors actually do anything when they're called.

I have been researching it and I've found that if I create a class with a function that calls its own destructor it doesn't do anything at all (i.e. all variables remain untouched and the instance still exists and is usable).

Does this mean that a class destructor can be thought of as an inherited virtual function that all classes have and a redefinition of it is possible (to delete pointers etc. and to clear member variables) but that if it's not redefined that it'll do nothing at all?

If so, couldn't a destructor essentially be used as a "clear all data" kind of function and make some parts of code more efficient by clearing a dynamically memory allocated variable and re-using it rather than getting the computer to find a new block of memory on the heap?

Thanks.

3

4 Answers

7

I have been researching it and I've found that if I create a class with a function that calls its own destructor it doesn't do anything at all (i.e. all variables remain untouched and the instance still exists and is usable).

Consider this code:

#include <iostream> struct A { ~A() { std::cout << "A::~A" << std::endl; } }; struct B { A a; }; int main() { B b; std::cout << "Calling b.~B()" << std::endl; b.~B(); std::cout << "Done" << std::endl; } 

You'll see that calling B's default destructor calls A's destructor, because B contains an A:

Calling b.~B() A::~A Done A::~A 

Only when b goes out of scope is the stack unwound and the synthesised B::~B() called and, in turn, A::~A() before their memory is free'd.

1

In addition to Notinlist's answer:

Default constructors call your base classes' constructors.

If so, couldn't a destructor essentially be used as a "clear all data" kind of function and make some parts of code more efficient by clearing a dynamically memory allocated variable and re-using it rather than getting the computer to find a new block of memory on the heap?

You're sort of describing a memory pool. If you want, your objects may acquire and return memory buffers to/from some pool system you invent. But for the most part allocations are fast enough and infrequent enough that it's not common (anymore) for people to do this. Not to say they are infrequent, but they need to be happening a lot to take notice of that performance hit.

Calling a destructor manually is generally a bad idea. The C++ FAQ section about destructors has plenty of good information about this.

If you do want to destroy an object explicitly you can use additional scopes to cause the destructor to be safely called (see this FAQ entry). This method also prevents you from using the object instance which has been destroyed. Although the instance may seem to be usable, it really is not.

If your intention is to free some, but not all, of the resources owned by an instance of a class you could try two things:

Suppose that your initial approach to manually calling a destructor worked, or you chose to do something that like the clear() method above, in both cases you may run into problems later.

A well understood and often practiced method of resource management in C++ is Resource Acquisition Is Initialization (often abbreviated RAII, but ignore the name if it is confusing, the concept is understandable). See this Wikipedia article or this answer for useful information.

Here is the tl;dr though:

Following this idiom will usually prevent C++ resource management problems before they occur.

2

ncG1vNJzZmirpJawrLvVnqmfpJ%2Bse6S7zGiorp2jqbawutJoaG1xYWV%2BeoSOnaZmnJWbrra402abnqukp8KkwM6rqmacn2Kur8XToaCnnw%3D%3D