Struggling with memory leaks in your program? Having problems with double deletions? In this first article in a two-part series, programming expert Bartosz Milewski describes in detail the resource-management methodology--one of the industrial-strength techniques used in the development of serious C++ applications.

This pair of articles is an edited and extended version of two articles Bartosz Milewski published in C++ Report in September 1998 and February 1999. Bartosz Milewski is the author of C++ In Action: Industrial-Strength Programming Techniques (Addison-Wesley, 2001, ISBN 0-201-69948-6), a book that teaches professional programming in C++.

Resources and Their Ownership

My favorite definition of a resource is "anything that your
program has to acquire and then release." Memory is of course the prominent
example of a resource. It's acquired using new and released using
delete. But there are many other types of resources—file handles,
critical sections, GDI resources in Windows, etc. It's convenient to
generalize the notion of a resource to encompass all objects created and
released in a program, the ones allocated on the heap as well as the ones
declared on the stack or in the global scope.

The owner of a given resource is an object or a piece of code
that's responsible for the resource's release. Ownership falls into
two classes—automatic and explicit. An object is owned
automatically if its release is guaranteed by the mechanisms of the
language. For instance, an object embedded inside another object is guaranteed
to be destroyed when the outer object is destroyed. The outer object is thus
considered to be the owner of the embedded object.

Similarly, every object that's declared on the stack (as an automatic
variable) is guaranteed to be released (destroyed) when the flow of control
leaves the scope in which the object is defined. In this case, the scope itself
is considered the owner of the object. Notice that automatic ownership is
compatible with all other mechanisms of the language, including exceptions. It
doesn't matter how you exit a scope—normal flow of control, a
break statement, a return, a goto, or a
throw—automatic resources are always cleaned up.

So far, so good! The problem starts with pointers, handles, and abstract
states. If access to a resource is through a pointer, as is the case with
objects allocated on the heap, C++ doesn't automatically take care of its
release. Instead, the programmer has to explicitly release the resource,
using the appropriate programming construct. For instance, if the object in
question was created by calling new, it should be deallocated by
calling delete. A file that was opened using CreateFile (Win32
API) should be closed using CloseHandle. A critical section entered
using EnterCriticalSection should be exited using
LeaveCriticalSection, etc. A "naked" pointer, file handle, or
a state of a critical section has no owner that would guarantee its eventual
release. The basic premise of resource management is to make sure that every
resource has its owner.

The First Rule of Acquisition

A pointer, a handle, a state of a critical section will have its owner only
if we encapsulate it in objects that follow the First Rule of Acquisition:
Allocate resources in constructors and release them in corresponding
destructors.

Once you encapsulate all resources according to this rule, you're
guaranteed not to have any resource leaks in your program. This is pretty
obvious if you only consider those encapsulating objects that are allocated on
the stack or are embedded inside other objects. But what about those that are
allocated dynamically? Not to worry! Anything that's allocated dynamically
is considered a resource, and consequently will also have to be encapsulated
according to the rule above. This chain of objects encapsulating objects
encapsulating resources has to end somewhere. It ends with the top-level owners,
which are either automatic or static. These are guaranteed to be released on
exiting the scope or the program, respectively.

Here's a classic example of resource encapsulation. In a multithreaded
application, the problem of sharing an object between threads is usually solved
by associating a critical section with such an object. Every client that wants
to access this shared resource has to first acquire the critical section. For
instance, this is how a critical section might be implemented in Win32:

The tricky part is that we have to make sure that each client entering the
critical section also exits it. The "entered" state of a critical
section is therefore a resource and should be encapsulated. The encapsulator is
traditionally called a lock:

Notice that, no matter what happens, the critical section is guaranteed to be
released by the mechanisms of the language.

There's one important thing to remember—each resource has to be
encapsulated separately. That's because resource allocation is almost
always a failure-prone operation, if only because there's always a finite
supply of any given resource. We'll assume that a failed resource
allocation might result in an exception—in fact, very often this is exactly
what should happen. So if you're trying to kill two birds with one stone,
or allocate two resources in one constructor, you might get into trouble. Just
think what happens when the first allocation succeeds and the second one throws.
Since the construction hasn't been completed, the destructor won't be
called, and the first resource will leak out.

This situation can be avoided easily. Whenever you have a class that requires
more than one resource, write small encapsulators for them and embed them in
your class. Every fully constructed embedding is guaranteed to be deleted, even
if the construction of the embedding object doesn't complete.