1

What is The Rule of Three? mentions

After executing the body of the destructor and destroying any automatic objects allocated within the body, a destructor for class X calls the destructors for X's direct [...] members [n3126.pdf 12.4 §6]

Which leaves me wondering, what's the use of a destructor if not to destroy the members? Please provide examples

Community
  • 1
  • 1
prongs
  • 9,422
  • 21
  • 67
  • 105
  • Where does it say *use of a destructor is not to destroy the members*?? – Alok Save May 27 '13 at 17:51
  • I think the Q&A you linked does provide examples – Andy Prowl May 27 '13 at 17:53
  • @AlokSave: the quotation says that the members are destroyed after executing (the body of) the destructor. I think it is a reasonable deduction from this, that the purpose of (the body of) the destructor is *not* to destroy the members. It's also true. – Steve Jessop May 27 '13 at 17:54
  • 3
    It can also close sockets, decrease reference counts, etc. – juanchopanza May 27 '13 at 17:54
  • You ask a very smart question, and you are onto something important. [You can read more](http://flamingdangerzone.com/cxx11/2012/08/15/rule-of-zero.html) about the Single Responsability Principle as it applies to destructors. – Luc Danton May 27 '13 at 19:09

5 Answers5

3

It is for additional cleanup that the members themselves are not responsible for. Or in the case of resource management to make sure the resources associated with he object are correctly released. Remember not all members have destructors that will be called (pointers don't have destructors). So if you have pointers you need to manually manage them.

Example resource management with pointers.

shared_ptr::~shared_ptr()
{
    if (decrementReferenceCountAndCheckForZero())
    {
        cleanupResources();
    }
}

Example. Working with frameworks. None of the members know about the framework but the worker does.

MyWorker::MyWorker()
{
     Framwork::Register(this);
}
MyWorker::~MyWorker()
{
    Framework::Unrigester(this);
}
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • Although in the case of the framework, for separation of responsibilities you might reasonably want a class `FrameworkRegistration` that handles the (un)registration, and then `MyWorker` has one as a data member. Basically, `Framework::Unregister` is not a very C++-friendly interface, but is easily wrapped in an interface that is C++-friendly. – Steve Jessop May 27 '13 at 18:11
  • @SteveJessop: Totally agree. Just swinging for potential examples. – Martin York May 27 '13 at 18:14
2

Anything associated to the class instance that needs disassociation/release/special handling once the object ceases to exist.
Few examples:

  • File handles opened, owned and used by the instance and wont be used post object destruction.
  • Socktes, mutex etc opened and owned by the class instance.
Alok Save
  • 202,538
  • 53
  • 430
  • 533
1

All that statement means is if you have a destructor defined as

Foo::~Foo()
{
    Bar b;
    b.do_whatever();
}

then the b object's destructor is run before the destructors of any of Foo's members. The body of the destructor is executed, and the automatic object allocated within the body, i.e. b, is destroyed first.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
1

Your class might manage resources that aren't released by calling the destructors of the data members of your object. If so, then the code to release the resource belongs in a destructor that you write.

For example if you allocate objects with new then they must be freed with delete. If you open a file with fopen then it's closed with fclose. If you take a Posix mutex with pthread_mutex_lock then it must be released with pthread_mutex_unlock.

For each kind of resource needs freeing you (or someone else) can write a class that manages and frees that resource, and provides access to its basic operations. Hence the existence of classes like std::unique_ptr, std::shared_ptr, std::lock_guard, std::fstream. Of course, for simplicity you usually want there to be only one class that manages a particular kind of resource. So, since std::lock_guard exists in C++11, the only reason that you'd write your own class to release a mutex would be if you're providing some alternative interface to the standard one. Classes with non-default destructors should ideally be rare in your own code -- often there already exist classes that you can use as data members or automatic variables, and whose destructors do the job.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
0

This might help you

Suppose a class is having array of someClass which is dynamically created . In your constructor suppose you created

someClass * p = new someClass [10] ;

then in destructor you would write

delete []p ;
MAG
  • 2,841
  • 6
  • 27
  • 47