The RAII Programming Idiom

I’m often surprised, and occasionally horrified, that Resource Acquisition Is Initialisation isn’t better known than it is amongst programmers who use languages to which it is applicable. It is a simple, eloquent and efficient way to deal with many situations where there is a risk of “leaking” memory or handles, failing to release file locks, etc.

Actually it generally is known by most programmers in applicable languages, and to some extent is supported by many common libraries and tools. Like many idioms and patterns you aren’t learning anything totally new when you learn about it, but you are making it something that you have more consciously integrated into your mental toolkit for solving programming problems.

Which Languages are Appropriate for RAII

Or rather, which languages is RAII appropriate for. As will soon be explained RAII depends on the way that constructors and, in particular, destructors, get called and the predictability of this happening.

RAII can be used with:

RAII cannot generally be used with languages that clean up objects using an unpredictable garbage collection, such as Java (however see the Postscript on .NET). If a language guarantees cleanup of all objects before an application shuts down then it may be applicable to some problems.

It’s worth noting that if you are using C++ with garbage collection (which isn’t defined by the language, but which may be provided by a run time) then that garbage collection will generally not apply to objects allocated on the stack and hence RAII can still be used.

Of course these are arguably differences in implementation rather than in the language itself, it depends on where you draw the line between language and runtime support. Inability to support RAII is reflected in the actual language of Java though in its use of the finally keyword to indicate actions which must take place after a try block is left whether an exception is thrown or not. Together with the ability to use catch(...) to catch all errors, RAII makes the finally unnecessary in C++ (which shares try and catch with Java).

The problem

Generally there will be some points in the execution of any moderately sized program where something is done which necessitates a later “undoing”. Examples of these are:

Generally the pattern is:

Obtain Resource - Use Resource - Release Resource

At this level of complexity the only real danger is that we simply forget to release the resource, which, while it does happen, is something that should be quickly caught in any code-review.

The problem becomes more difficult if the period between obtaining and releasing the resource becomes more complicated, with many different points at which the resource should be released:

Obtain Resource - Go through many possible forks all of which end in - Release Resource

Here what we had previously labelled “Use Resource” is now more complicated and as such there are frequent points at which we may wish to release the resource.

One solution to this is to make all of this decision-making and forking is to tie all of the different paths together into one self-contained unit and effectively make the above diagram follow the pattern of the first again. This is one of the reasons that many programmers in some languages consider leaving a function or subroutine at more than one point to be poor style (another is that in some languages, it just looks ugly, certainly there seems to be more effort made to have a single point where a function is exited in VB than in C). However if some of the forking might be because of exceptions being thrown then you cannot always ensure that this is done without working against the exception mechanism.

The Solution

The solution is to make the first and second part of the pattern, obtaining and releasing the resource, self-contained rather than the middle part.

This is easily done with the constructor and destructor of a class.

In C++ the general form is:

class someResource{
    //internal representation holding pointers, handles etc.

public:
    someResource(){
        //Obtain resource.
    }

    ~someResource(){
    //Release resource.
    }

};

In VB6 the general form is:

'Internal representation holding handles etc.

Private Sub Class_Initialize()
    'Obtain resource.
End Sub

Private Sub Class_Terminate()
    'Release resource.
End Sub

The obvious next step is to add public functions to these classes that enable them to be used directly instead of the lower-level access to the resource. Indeed even if you are unfamiliar with the RAII idiom you have probably built classes just like the above for exactly that reason.

A few things are worth noting here.

The first is that if obtaining the resource requires parameters of some sort (e.g. the name of a file to obtain file handle) then the C++ version can easily accommodate that by taking an argument to the constructor. With VB6 we need to add an initialisation function to actually obtain such a resource. This brings on quite a few issues though at least these issues are isolated to a single class and can largely be dealt with them there. (Sometimes C++ classes are built in similar ways, See [RECTOR] for examples of classes that do this and a justification for the technique, See [STROUSTRUP] for a, to my mind more convincing, argument against this).

The second is that the constructor and destructor of the C++ version are inline. This is typical of such classes, where the actual code we need to use to execute is pretty simple often a single call into a library routine. These classes often have nothing but inline functions as all the real work gets done elsewhere; they’re wafer-thin and melt in the compiler’s mouth.

Similarly there the destructor isn’t virtual. Again this is to help the compiler inline the calls. As a rule these classes aren’t used as public bases of other classes, and even if they were those classes wouldn’t generally be destroyed by a call to the destructor of the base. Of course if there is any risk of this happening a virtual destructor will be vital to prevent leaks.

Using an RAII Class

Using an RAII class is simplicity itself. You just create it when you need to use the resource in question. Whenever it falls out of scope the resource will be released without any further action from you.

RAII in Well-Known COM Components

Because COM uses reference-counting garbage collection COM objects can be used as RAII objects (indeed I said you could use VB6 classes for RAII and internally all VB6 classes “look” like COM even if they aren’t exposed as such).

A good example is the classes provided by calls to the FileSystemObject. File and TextStream objects will call Close() when they are destroyed if necessary, so while RAII is not the primary advantage they give over other mechanisms (they are simpler than some alternatives, and the only out-of-the-box way to deal with files in script) they have all the advantages of RAII.

Of course a pointer to a COM object is in itself a resource that must be carefully managed. If you are using a scripting language or VB6 then the calls to AddRef() and Release() are managed for you, but in C++ they must be carefully matched. The CComPtr and CComQIPtr templates provided by ATL use RAII techniques to take much of this burden off the programmer, as is the _com_ptr_t templates provided by VC++ if you #import without the no_smart_pointers attribute.

RAII in the STL

The Standard Template Library makes use of the RAII technique in many places. The file stream templates (std::basic_ifstream, std::basic_ofstream and std::basic_fstream) for example will close the file stream on destruction if close() hasn’t yet been called.

RAII is also directly supported by the std::auto_ptr template. Its destructor will call delete on the pointer if it “owns it” (it will for instance stop “owning” a pointer if it is assigned to another std::auto_ptr). Hence it uses RAII to prevent memory leaks.

Costs and Benefits

Run-time Performance

The runtime performance costs of this technique obviously depend on quite a few factors.

In C++ the cost is typically nil, or an actual improvement in runtime performance over alternative techiques. As these classes have inline non-virtual constructors and destructors the code produced by an optimising compiler should be pretty much identifcal to that of the equivalent using explicit resource acquisition and release. The class will also typically use no memory, or no more than would have been necessary through other methods.

In cases where the code executed between acquisition and release is more complicated, and in particular where there are a wide variety of possible exceptions that could be thrown, this technique is typically more efficient than alternative techniques which involve either checking state or catching exceptions to rethrow them after perfoming the necessary cleanup.

In cases where the acquisition and/or release is itself complicated the runtime complexity generally increases at the same or a slower rate with RAII than with alternative techniques, and at this point efficiency itself is a good reason to consider RAII. It’s worth noting that even if a virtual destructor is needed for an RAII class it is generally possible for the virtual selection mechanism to be performed at compile-time rather than through the vector table (or whatever implementation of virtual functions is used) — since the compiler knows the exact type of the object it does not need to use the virtual mechanism at run-time.

In VB6 the cost is typically greater. All VB6 classes are internally COM classes. As such they all have implementations of IUnknown (and IDispatch), a reference count, a degree of thread-safety, are created on the heap, and their creation and destruction is controlled by virtual calls to AddRef() and Release().

It appears from experimentation that these features are not optimised away by the compiler, certainly not the implementation of IUnknown.

This means that in designing VB6 programs we cannot use RAII quite as freely as in C++. The benefits far outweigh the costs in cases where analysis of the possible conditions is daunting and liable to change, in less complicated cases the decision is more difficult to make.

Notational Costs and Benefits

In all languages the effects of RAII on the readability of code will depend largely on how clear the purpose and semantics of the RAII class is. As I’ll go into in more detail later, an RAII class should be considered a design tool and its use a notational benefit to the function in which it is used.

Because RAII is better known in C++ than VB a class that exists primarily for RAII purposes may seem a bit “foreign” to a VB coder. Alternatively VB coders are generally used to classes cleaning up after themselves completely and will expect RAII behaviour when a class is used to give access to a resource. C++ coders will not necessarily expect this, though at all but the lowest levels of abstraction any class that does not exhibit such behaviour is poorly designed.

There is often a slight increase in the complexity of “stepping through” code in a debugger if you step into the class’s constructor and destructor. However once the class is tested, trusted, and well known these can be stepped over and the task of stepping through code is simplified.

There is generally a run-time performance hit when debugging even in C++. But worries about run-time performance of a debug build are obviously misguided.

RAII in Design

The main reason for studying programming idioms and patterns is so that we can consciously use them in our designs. From a design perspective there are two different times when we use RAII.

The first kind of class is one that is designed purely, or at least primarily, to provide RAII semantics. The STL’s std::auto_ptr template is a classic example of that. It is small, light and typically calls to its members, including the constructor and destructor, will be inlined and optimised away to the equivalent hand-written code. A notable feature of this class is that it does not protect the user from the effects of derefencing a null pointer. With a more generalised attempt to protect the user from the possible pitfalls of pointers we would expect such an attempt to throw an exception. However the standard ([ISO/IEC 14882]) defines operator*() and operator->() with throw() to forbid exception throwing. This is a very low-level class and should be used appropriately. It’s worth noting that the very fact that RAII can be used in such low-level situations reflects how efficient the mechanism is.

The second kind of class is one that is designed to give access to a resource at an appropriate level of abstraction, and which provides RAII semantics as they apply to the resource in question in addition to other functionality. Examples would be both the STL and COM methods for dealing with file objects. When these classes are destroyed the close their files.

There is a level of abstraction above which RAII semantics must be provided if there are any resources managed by the class. At high levels of abstraction a programmer should not have to think about the underlying resources, indeed it should be possible to change the nature of those underlying resources without the higher-level code having to be changed. At this point it largely ceases to be RAII and becomes a matter of the basic pre-conditions, post-conditions and invariants of the class’s design.

In these cases the RAII semantics are often not free. For example in the cases of the file classes mentioned all of these classes enable users to close the file before the class is destroyed, so the destructor has to check that the file is open before closing it. Also they are often destroyed via pointers requiring virtual calls to the destructor and so on. However these facts are inherent in the increase in abstraction rather than RAII itself. They are also generally over-estimated by those coders obsessed with efficiency and we should avoid over-stating them. They aren’t free, but they are very cheap.

Designing Pure RAII Classes

The important features of pure RAII classes like std:auto_ptr are efficiency, transparency, and reliability.

Efficiency
Typically these classes should have little or no run-time disadvantages compared to alternative methods. They typically are “free-standing”, without any public bases, have no virtual functions, and have only inline functions. Their internal representation is generally the absolute minimum for the tasks the perform, often nothing more than one variable which contains the type used by the lower-level functionality wrapped (a file handle, window handle, pointer to memory, etc.) Often their representation is a reference to an object created by external operations. In this case the reference can often be optimised away.
Transparency
Use of the class should generally be equivalent to, or a more user-friendly version of, use of the underlying resource. Use of an std::auto_ptr through * or -> is identical to use of a pointer. The ATL win class provides all the Windows API functions, but as member of the class. Often it is appropriate to allow these types to be cast to the types of their underlying representation.
Reliability
The whole purpose of using a pure RAII class is to gain reliable control over some potentially dangerous aspect of the underlying resources behaviour. Obviously this control must be provided. It is important that documentation state clearly which features are or are not made safer. For example a user might expect it to become safe to dereference a null std::auto_ptr were it not made clear that there is no extra protection offered in this case (of course an auto_ptr like class that does provide such protection can be easily created if appropriate).

Designing Classes with RAII Semantics Along with Other Features

With higher level classes RAII is generally taken for granted by users. Certainly any class that is part of the public interface of a component or library that is not specifically geared towards low-level use should clean up after itself correctly or its design is clearly flawed.

At this level of abstraction the real question is to make sure that the RAII behaviour is reliable and error-free. Often using lower-level RAII classes as part of the internal representation is a good way to do this.

The design of any class should consider the state that exists before and after creation, before and after destruction, and invariants that will exist before and after any function is called on a fully constructed object. RAII helps this design task.

With classes that are not easily labelled “low level” or “high level” design becomes somewhat less clear-cut. Not only is RAII not a given with low level classes, but it is often inappropriate at that level (when a class deals with a resource, but does not “own” it). You should have a good idea of exactly what level of abstraction a class operates at, and should communicate this clearly to the class’s user. A class which doesn’t seem to fit well at a single level of abstraction is almost invariably a poorly-designed class.

RAII Inside Classes

RAII classes can be particularly useful when the scope which governs their lifetime is another class. Where this comes into its own is in cases where constructors or destructors can throw exceptions.

In C++ the order of construction is that first the base, and then all member objects are constructed in the order of their declaration. Then the constructor’s body (if any) is executed. This is conceptually recursive, with the same process happening to any member objects of member objects, though with inline constructors this recursion doesn’t really involve the overhead of a function call.

The order of destruction is the opposite, first the body of the destructor is called, then the destructors for member objects, then the destructor of the base.

This means that if a member object with RAII semantics has been created and an exception happens before the constructor has completed then its destructor will be called as part of the stack unwinding. Hence an object which controls multiple resources can guarnatee their cleanup even if it isn’t fully constructed by using member RAII objects.

Further, if there is a dependency between the acquisition and release of two or more resources they generally tend to be nested, that is the first resource acquired must be the last released. This naturally matches the order of construction and destruction of C++ classes.

One thing to be careful of is the danger of throwing exceptions in destructors. This is generally true whether a class uses RAII or not. If a destructor is being executed during the process of an exception being thrown (most often because of stack-unwinding) and it throws an exception then, as always if an exception is thrown while another exception is currently being thrown, terminate() will be called.

Some people say that you should never allow an exception to escape a destructor. This isn’t strictly true, though it is a good principle to follow when possible. Since an RAII class is designed with exception safety in mind, it is wise to avoid giving them destructors that can throw exceptions. However the very nature of their destructors means it is often important that they can throw exceptions. Calling uncaught_exception() allows a destructor to check if it can throw an exception without calling terminate(). However you may decide that calling terminate() is appopriate, particularly for small programs that can signal failure to complete through their return code.

In VB there isn’t the same guarantee about order of destruction of member objects, but the same general principle applies.

RAII and Component Design

We’ve seen how RAII can help the design of individual classes and functions, and what is involved in the design of RAII classes themselves. When looking at the wider scope of a component, library or application RAII stops being about exception-handling mechanisms, and becomes part of the overall exception-management strategy.

RAII answers a lot of cases where some developers avoid conventional exception mechanisms in favour of other techniques (such as returning values indicating failure, or setting global error number variables) with the myriad problems they bring.

RAII adds resiliance to code that cannot know what exceptions may be thrown, in particular code that calls virtual functions, or code that calls functions which depend upon template arguments.

RAII makes it easier to allow exceptions which are the “concern” of other components to pass through them from the component that threw the exception to the component that will catch it. This helps you to guarantee good exception-safe behaviour without knowledge of the exceptional circumstances that will be involved.

Sentry Classes

A generalisation of the RAII class is the sentry class. A sentry class is any class which (optionally) performs some action on construction, and then performs some action on destruction. RAII classes are sentry classes where the sentry actions acquire and release resources. Sentry classes for dealing with critical sections and monitors are RAII or not depending on whether you consider critical sections and monitors to be resources. This generalisation of the RAII idiom is also called the “Execute Around” pattern, though that term is also used for other mechanisms (such as the use of finally in Java).

Implementations of the STL streams use sentry classes to deal with various matters, such as locale-specific whitespace-skipping, management of tied streams, etc. Which must be called before or after certain stream operations in an efficient and flexible manner.

Summary

If you thought you didn’t know the RAII idiom when you started reading this, you’re quite likely thinking “Well duh! Everyone does that”. However in giving it a name and examining it will be more readily to hand when you have a design problem it will help solve. RAII is an simple but important example of such.

References

ISO/IEC 14882
ISO (International Organization for Standardization), ISO/IEC 14882:1998. Programming Languages — C++, (Bound under the title The C++ Standard), International Organization for Standardization
RECTOR
Brent Rector and Chris Sells, ATL Internals, Addison-Wesley Pub Co, 1999
STROUSTRUP
Bjarne Stroustrup, The C++ Programming Language (3rd Edition), Addison-Wesley Pub Co, 2000
(See also, the special edition of this book).

Postscript — A Note on .NET

.NET uses non-deterministic garbage collection, much like Java, and RAII techniques are not directly applicable to .NET.

C# offers the using keyword (different from using in C++, although there is support for using directives, but not for using declarations, in C# as well). A using statement will cause System::IDisposable::Dispose to be called on the affected object when it goes out of scope, allowing for some RAII-like functionality.

Managed Extensions for C++ do not offer such a new use for using. Nemanja Trifunovic has written RAII Idiom and Managed C++ which addresses this, and indeed goes beyond what is offered to C# programmers through using, and I recommend it to all Managed C++ hackers.

Jon HannaSkip Buttons This work is licensed under a Creative Commons License. Email Me Hacker Amazon Wishlist Thinkgeek Wishlist

Valid XHTML 1.0 Valid CSS UTF-8 Encoded
Amazon.com Associate Amazon.co.uk Associate
Viewable in any browser Best viewed at a resolution you like!
Coded By Hand Uploaded Using Filezilla