Home C++ Introduction Decisions Loops Input/Output Functions Stack and Heap References Arrays Searching and Sorting Recursion Pointers Character and Strings Structures Classes Inheritance Exceptions Templatess STL Modern C++ Misc Books ----

Classes


Contents

Destructors

Similar to a constructor we have a destructor method. A destructor is called when an object is destroyed. This will happen for objects that are created on the stack when they go out of scope.
File: destruct1.cpp
#include <iostream>
using namespace std;

class Package
{
  private:
    int value;
  public:
    Package()
      {
        value = 7;
        cout << "Constructor:" << value << endl;
      }
    Package(int v)
    {
        value = v;
        cout << "Constructor:" << value << endl;
    }
    ~Package()
        {
            cout << "Destructor:" << value << endl;
        }
};

int main()
{
    Package obj1(4);
    Package obj2 ;
    Package obj3(2);
    return 0;
}
$ g++ destruct1.cpp ; ./a.exe
Constructor:4
Constructor:7
Constructor:2
Destructor:2
Destructor:7
Destructor:4
We see the destructor getting called when the objects go out of scope. The way these objects are created on the stack is normally in the manner:
Stack

obj3

obj2      ^

obj1      |

The "obj3" is destroyed first and then obj2 and
then obj1. We can see that the destructor for
"obj3" got called first. Objects on the stack
are destroyed in the reverse order of their creation.

Notice we used:

 Package obj2 ;

If we used

 Package obj2() ;
then the code also compiles but it means something else. It means that it is a declaration of a function ! The name of the function is "obj2" and it returns an object of type Package. So we declared a function but did not receive an error during compilation. That's because we didn't use it. The following example shows the compilation error.
File: destruct2.cpp
#include <iostream>
using namespace std;

class Package
{
    private:
    int value;
    public:
    Package()
    {
        value = 7;
        cout << value << endl;
    }
        Package(int v)
        {
            value = v; cout << value << endl;
        }
        ~Package()
        {
                cout << value << endl;
        }

};


int main()
{
    Package obj1(4);
    //Package obj5(5);
    Package obj2()  ;
    Package obj3(2) ;
    obj2() ;

return 0;  }
$ g++ destruct2.cpp
destruct2.cpp: In function ‘int main()’:
destruct2.cpp:30:21: warning: empty parentheses were disambiguated as a function declaration [-Wvexing-parse]
   30 |         Package obj2()  ;
      |                     ^~
destruct2.cpp:30:21: note: remove parentheses to default-initialize a variable
   30 |         Package obj2()  ;
      |                     ^~
      |                     --
destruct2.cpp:30:21: note: or replace parentheses with braces to value-initialize a variable
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/ld: /tmp/ccKonALR.o:destruct2.cpp:(.text+0x3a): undefined reference to `obj2()'
collect2: error: ld returned 1 exit status
To destroy an object on the heap we have to use the "delete" method.
File: destruct3.cpp
#include <iostream>
using namespace std;

class Package
{
    private:
    int value;
    public:
    Package()
    {
        value = 7;
        cout << "Constructor:" << value << endl;
    }
    void print()
    {
        cout << "Inside print method:" << value << endl;
    }
    Package(int v)
    {
        value = v;
        cout << "Constructor:" <<  value << endl;
    }
    ~Package()
    {
        cout << "Destructor:" << value << endl;
    }
};

 int main()
 {
     Package* obj1 = new Package(4);
     Package* obj2  = new Package()  ;
     Package* obj3 = new Package(3) ;
     obj1->print() ;  (*obj1).print() ;
     //Setting the pointer to NULL will not destruct the object
     //Object destruction can only happen with delete.
     //obj1 = NULL ;
     delete( obj1 ) ;
     delete ( obj2 ) ;
     delete ( obj3 ) ;
     return 0;
}
$ g++ destruct3.cpp  ; ./a.exe
Constructor:4
Constructor:7
Constructor:3
Inside print method:4
Inside print method:4
Destructor:4
Destructor:7
Destructor:3
Couple of points to note about creation of objects. We have to use the "new" notation but for default constructor we have to use :
Package* obj2  = new Package()  ;

where as when creating objects with a constructor
that does not take any arguments on the stack we used:

Package obj2 ;

When we access a member we can use:

obj2->print() ;

We can also do:

 (*obj1).print() ;

When we say (*obj1) we are specifying that the obj1
is a pointer and we want the object that it's pointing
to. Once we have that we can use the regular notation of
using "." to access the method.

 //obj1 = NULL ;
Note that setting a pointer variable to NULL does not destroy an object. In fact it prevents us from destroying an object as we have lost the address that existed in the pointer variable. The only way to destroy the object on the heap is through the "delete" call. That call can be made at any time; in another function. If the memory is never freed then it still occupies space in the heap and we have introduced something called a memory leak. If this process is repeated then at some point we will run out of heap space.