Balancing and Exceptions

Balancing and Exceptions

Languages that support exceptions can make resource deallocation tricky. If an exception is thrown, how do you guarantee that everything allocated prior to the exception is tidied up? The answer depends to some extent on the language.

Balancing Resources with C++ Exceptions

C++ supports a trycatch exception mechanism. Unfortunately, this means that there are always at least two possible paths when exiting a routine that catches and then rethrows an exception:

  void  doSomething(  void  ) {       Node *n =  new  Node;       try {         //  do something  }       catch (...) {  delete  n;         throw;       }  delete  n;     } 

Notice that the node we create is freed in two placesonce in the routine's normal exit path , and once in the exception handler. This is an obvious violation of the DRY principle and a maintenance problem waiting to happen.

However, we can use the semantics of C++ to our advantage. Local objects are automatically destroyed on exiting from their enclosing block. This gives us a couple of options. If the circumstances permit, we can change "n" from a pointer to an actual Node object on the stack:

  void  doSomething1(  void  ) {       Node n;       try {         //  do something  }       catch (...) {         throw;       }     } 

Here we rely on C++ to handle the destruction of the Node object automatically, whether an exception is thrown or not.

If the switch from a pointer is not possible, the same effect can be achieved by wrapping the resource (in this case, a Node pointer) within another class.

 //  Wrapper class for Node resources   class  NodeResource {       Node *n;  public:  NodeResource() { n =  new  Node; }       ~NodeResource() {  delete  n; }       Node *  operator  ->() {  return  n; }     };  void  doSomething2(  void  ) {       NodeResource n;       try {         //  do something  }       catch (...) {         throw;       }     } 

Now the wrapper class, NodeResource, ensures that when its objects are destroyed the corresponding nodes are also destroyed. For convenience, the wrapper provides a dereferencing operator ->, so that its users can access the fields in the contained Node object directly.

Because this technique is so useful, the standard C++ library provides the template class auto_ptr, which gives you automatic wrappers for dynamically allocated objects.

  void  doSomething3(  void  ) {       auto_ptr<Node> p  (new  Node);       //  Access the Node as p->...  //  Node automatically deleted  at  end  } 

Balancing Resources in Java

Unlike C++, Java implements a lazy form of automatic object destruction. Unreferenced objects are considered to be candidates for garbage collection, and their finalize method will get called should garbage collection ever claim them. While a convenience for developers, who no longer get the blame for most memory leaks, it makes it difficult to implement resource clean-up using the C++ scheme. Fortunately, the designers of the Java language thoughtfully added a language feature to compensate, the finally clause. When a try block contains a finally clause, code in that clause is guaranteed to be executed if any statement in the try block is executed. It doesn't matter whether an exception is thrown (or even if the code in the try block executes a return )the code in the finally clause will get run. This means we can balance our resource usage with code such as

  public void  doSomething()  throws  IOException {       File tmpFile =  new  File(tmpFileName);       FileWriter tmp =  new  FileWriter(tmpFile);  try  {         //  do some work  }  finally  {         tmpFile.delete();       }     } 

The routine uses a temporary file, which we want to delete, regardless of how the routine exits. The finally block allows us to express this concisely.



The Pragmatic Programmer(c) From Journeyman to Master
The Pragmatic Programmer: From Journeyman to Master
ISBN: 020161622X
EAN: 2147483647
Year: 2005
Pages: 81

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net