To avoid resource leaks in the presence of exceptions, we can encapsulate resources inside objects.
Using objects to manage pointer-based resource
Suppose we’re writing software for a shelter names Adorable Little Animals, an organization that finds homes for puppies and kittens. Each day the shelter creates a file containing information on the adoptions it arranged that day, so we need to read these files and do the approgriate procesing for each adoption.
A reasonable design will use polymorphism: an abstract base class ALA (“adorable little animal”), with two concrete derived classes for puppies and kittens, and a virtual function processAdoption to handle the necessary species-specific processing:
|
|
Another thing we need is a virtual constructor (MECpp item 25), which reads information from a file and produce either a Puppy object or a Kitten object, depending on the information in the file:
|
|
Finally, the key processing part of the program looks like this:
|
|
However, there’s a potential resource leak: if pa->processAdoption threw an exception, all statements in processAdoptions after this statement would be skipped, ending up with pa never getting deleted. To solve it, an ungly design would be:
|
|
The duplication in cleanup code is annoying to write and difficult to maintain. Remember that
Local objects are always destroyed when leaving a function, regardless of how that function is exited 1.
So we can move the delete into a destructor for an object local to processAdoptions, which is exactly the functionaltity smart pointers in standard C++ library provide. For example, the essential of auto_ptr (item 13, MECpp item 28) boils down to following definition:
|
|
New processAdoptions using an auto_ptr object instead of a raw pointer:
|
|
Using objects to manage other resources
The idea behind auto_ptr is to use an object to store a resource that needs to be automatically released via the object’s destructor, which applis to broader ranges of resource types as well. For example, in a GUI application that needs to create a window to display some information:
|
|
The functions createWindow and destroyWindow for acquiring and releasing window resources should be packaged in an object to avoid resource leak in the situations where an exception is thrown during process of displaying info in w:
|
|
Note that the implicit conversion operator is essential to the practical application of a WindowHandle object, becauce it means we can use a WindowHandle just about anywhere we would normally use a raw WINDOW_HANDLE (refer to MECpp item 5 for downsides of doing so).
Given this WindowHandle class, we can rewrite desplayInfo as follows:
|
|
-
The only exception to this rule is when we call
longjmp, and this shortcoming oflongjmpis the primary reason why C++ has support for exceptions in the first place. ↩︎