Bruce Eckel's Thinking in C++, 2nd Ed Contents | Prev | Next

Guaranteed cleanup with the destructor

As a C programmer, you often think about the importance of initialization, but it’s rarer to think about cleanup. After all, what do you need to do to clean up an int? Just forget about it. However, with libraries, just “letting go” of an object once you’re done with it is not so safe. What if it modifies some piece of hardware, or puts something on the screen, or allocates storage on the heap? If you just forget about it, your object never achieves closure upon its exit from this world. In C++, cleanup is as important as initialization and is therefore guaranteed with the destructor.

The syntax for the destructor is similar to that for the constructor: The class name is used for the name of the function. However, the destructor is distinguished from the constructor by a leading tilde ( ~). In addition, the destructor never has any arguments because destruction never needs any options. Here’s the declaration for a destructor:

class Y {
public:
  ~Y();
};

The destructor is called automatically by the compiler when the object goes out of scope. You can see where the constructor gets called by the point of definition of the object, but the only evidence for a destructor call is the closing brace of the scope that surrounds the object. Yet the destructor is still called, even when you use goto to jump out of a scope. ( goto still exists in C++, for backward compatibility with C and for the times when it comes in handy.) You should note that a nonlocal goto, implemented by the Standard C library functions setjmp( ) and longjmp( ), doesn’t cause destructors to be called. (This is the specification, even if your compiler doesn’t implement it that way. Relying on a feature that isn’t in the specification means your code is nonportable.)

Here’s an example demonstrating the features of constructors and destructors you’ve seen so far:

//: C06:Constructor1.cpp
// Constructors & destructors
#include <iostream>
using namespace std;

class Tree {
  int height;
public:
  Tree(int initialHeight);  // Constructor
  ~Tree();  // Destructor
  void grow(int years);
  void printsize();
};

Tree::Tree(int initialHeight) {
  height = initialHeight;
}

Tree::~Tree() {
  cout << "inside Tree destructor" << endl;
  printsize();
}

void Tree::grow(int years) {
  height += years;
}

void Tree::printsize() {
  cout << "Tree height is " << height << endl;
}

int main() {
  cout << "before opening brace" << endl;
  {
    Tree t(12);
    cout << "after Tree creation" << endl;
    t.printsize();
    t.grow(4);
    cout << "before closing brace" << endl;
  }
  cout << "after closing brace" << endl;
} ///:~

Here’s the output of the above program:

before opening brace
after Tree creation
Tree height is 12
before closing brace
inside Tree destructor
Tree height is 16
after closing brace

You can see that the destructor is automatically called at the closing brace of the scope that encloses it.

Contents | Prev | Next


Contact: webmaster@codeguru.com
CodeGuru - the website for developers.
[an error occurred while processing this directive]