2

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.

Edward
  • 235
  • 4
  • 18
  • If call a destructor to manually free memory, what would happen if the object is then destructed? I'm not sure what you are aiming at, but it is probably better suited to a simple member function. – Bingo Feb 16 '13 at 12:24
  • The answer to this question may help:http://stackoverflow.com/questions/1036019/does-calling-a-destructor-explicitly-destroy-an-object-completely – Josh Peterson Feb 16 '13 at 12:30
  • Consider using memory pools or placement new/delete rather than this kind of optimization. And remember that: "premature optimization is the root of all evil". – mip Feb 16 '13 at 13:08

4 Answers4

2
  • 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.
Notinlist
  • 16,144
  • 10
  • 57
  • 99
  • What I meant by 'virtual' was that every class gets one by default (and can call it) but it just doesn't do anything; I didn't mean in the sense of inheritance :). But does this mean that any member variables of the class that are a structure or a class will have their destructors called as well? – Edward Feb 16 '13 at 13:22
  • @Edward Yes. Implicitly, always. If you do write a destructor for your class you still not have to call the descructors of your members. You just have to take care about `delete`-ing dynamically allocated objects, closing open files and releasing other resources associated with your object. If you don't have things like that then you don't need to write a destructor. – Notinlist Feb 16 '13 at 13:46
  • 2
    The point about inheritance is misleading: it’s entirely safe to have a base class with non-virtual destructor. The only time when a destructor should be virtual is when you intend to use the static type of the base class in runtime polymorphism (in other words, when you are going to access an instance with dynamic type “derived class” via a pointer / (non-const) reference of type “base class”). – Konrad Rudolph Feb 16 '13 at 13:46
  • @KonradRudolph Which I consider very likely if you start doing subclassing / interfacing. I think it is a good practice to have virtual destructor in base classes in general. The price does not matter that much. On the rare occasion that it is, then it can be reasoned indivudally. – Notinlist Feb 16 '13 at 14:00
  • @Notinlist No. It’s extremely common practice to have base classes in C++ that don’t use virtual destructors. For instance, most standard library implementations use this in the code of most container classes. It’s also used in countless idioms, such as policy classes, mixins and CRTP and in all these cases there’s a real incentive not to have a virtual destructor – in fact, some use-cases *rely* on this (because otherwise the advantage of the pattern is moot). – Konrad Rudolph Feb 16 '13 at 14:26
  • @KonradRudolph STL: Are they intended to be bese classes? Other things: OK. Will do a detailed check. But AFAIK, those are not novice subjects. – Notinlist Feb 17 '13 at 15:21
  • @Notinlist They are used as base classes **within the STL implementation**. Things like `std::vector` are *not* supposed to be used as base classes, though. – Konrad Rudolph Feb 17 '13 at 15:47
2

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.

johnsyweb
  • 136,902
  • 23
  • 188
  • 247
  • Thanks @Kleist, I simplified my code at one point but forgot to update the output. http://ideone.com/8fxvWQ shows it running as stated. – johnsyweb Feb 16 '13 at 13:09
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.

David
  • 27,652
  • 18
  • 89
  • 138
1

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.

Community
  • 1
  • 1
Josh Peterson
  • 2,299
  • 19
  • 21
  • I'm still unsure as to why explicity calling a destructor is a bad idea though. Provided the destructor has guards in it before deleting variables such as pointers (e.g. if( pointer != nullptr) delete pointer;) then surely it shouldn't be harmful. Is it just in case the programmer forgets what is and isn't destroyed by default by the destructor (e.g. member variables or inherited classes that will have their destructors called)? – Edward Feb 16 '13 at 13:42
  • @Edward No, that’s completely wrong. First of all, that guard doesn’t do *anything*, it’s useless. Second of all, even a valid guard would be no protection – even a default destructor must not be called several times because it calls the destructor of all member variables (see Notinlist’s answer). Lastly, you *can* call the destructor manually but you have to be *very* careful because, like I said, it is *not* allowed for the destructor to be called repeatedly, so you have to prevent any subsequent *automatic* calls to it. – Konrad Rudolph Feb 16 '13 at 13:50