![](https://cdn.statically.io/img/cdn.sstatic.net/Sites/stackoverflow/Img/apple-touch-icon@2.png)
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.
34 Answers
- Default constructor calls the default constructor of all member variables, not including primitive types (char, int, pointers).
- Destructor can be called explicitly, but it does not mean the dellocation of the object. If the object is on the stack, then it can not possibly do anything with it.
- Destructors are not virtual by default, but they really should be if you plan to inherit from the class.
- If the object is deallocated (goes out of scope, deleted from heap, or enclosing object is desctucted by any means) the desctuctor will be 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).
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.
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:
- Define a
clear()
(or similar) method on the class. - Ensure that the invariant of the class is maintained after
clear()
is called.
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:
- The lifetime of a resource should always be tied to the lifetime of an object.
- The lifetime of an object begins when the constructor completes
- The lifetime of an object ends when the destructor completes.
Following this idiom will usually prevent C++ resource management problems before they occur.
2ncG1vNJzZmirpJawrLvVnqmfpJ%2Bse6S7zGiorp2jqbawutJoaG1xYWV%2BeoSOnaZmnJWbrra402abnqukp8KkwM6rqmacn2Kur8XToaCnnw%3D%3D