Resource Acquisition Is Initialization
The technique was invented by Bjarne Stroustrup to deal with resource deallocation in C++. In this language, the only code that can be guaranteed to be executed after an exception is thrown are the destructors of objects residing on the stack.
RAII is vital in writing exception-safe C++ code: to release resources before permitting exceptions to propagate (in order to avoid resource leaks) one can write appropriate destructors once rather than dispersing and duplicating cleanup logic between exception handling blocks that may or may not be executed.
RAII can be used with:
- Languages which can have user-defined types allocated on the stack (“automatic” objects in C/C++ terminology) and cleaned up during normal stack cleanup (whether because of a function returning, or an exception being thrown). E.g. C++.
- Languages which have reference-counted garbage collection and hence predictable cleanup of an object for which there is only one reference. E.g. VB6
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.
C++ and D allow objects to be allocated on the stack and their scoping rules ensure that destructors are called when a local object’s scope ends. By putting the resource release logic in the destructor, C++’s and D’s scoping provide direct support for RAII.
The C language does not directly support RAII, though there are some ad-hoc mechanisms available to emulate it. However, some compilers provide non-standard extensions that implement RAII. For example, the “cleanup” variable attribute extension of GCC is one of them.
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.
RAII only ensures that the resource in question is released appropriately; care must still be taken to maintain exception safety. If the code modifying the data structure or file is not exception-safe, the mutex could be unlocked or the file closed with the data structure or file corrupted.
Local variables easily manage multiple resources within a single function: They are destroyed in the reverse order of their construction, and an object is only destroyed if fully constructed. That is, if no exception propagates from its constructor.
Resource management without RAII
In Java, objects are not allocated on the stack and must be accessed through references; hence, one cannot have automatic variables of objects that “go out of scope”. Instead, all objects are dynamically allocated. In principle, dynamic allocation does not make RAII unfeasible per se; it could still be feasible if there were a guarantee that a “destructor” (“finalize”) method would be called as soon as an object were pointed to by no references (i.e., if the object lifetime management were performed according to reference counting).
However, Java objects have indefinite lifetimes which cannot be controlled by the programmer, because, according to the Java Virtual Machine specification, it is unpredictable when the garbage collector will act. Indeed, the garbage collector may never act at all to collect objects pointed to by no references. Hence the “finalize” method of an unreferenced object might never be called or be called long after the object became unreferenced. Resources must thus be closed manually by the programmer, using something like thedispose pattern.
Disadvantages of scope bound resource management alternatives
Where both finalizers and closure blocks work as a good alternative to RAII for “shallow” resources, it is important to note however that the compositional properties of RAII differ greatly from these scope bound forms of resource management. Where RAII allows for full encapsulation of resources behind an abstraction, with scope bound resource management this isn’t the case. In an environment that purely depends on scope bound resource management, “being a resource” becomes a property that is transitive to composition. That is, using only scope bound resource management, any object that is composed using a resource that requires resource management effectively itself becomes a resource that requires resource management. RAII effectively breaks the transitivity of this property allowing for the existence of “deep” resources to be effectively abstracted away.
Lets for example say we have an object of type A that by composition holds an object of type B that by composition holds an object of type C. Now lets see what happens when we create a new implementation of C that by composition holds a resource R. R will have some
release method that must be invoked prior to C going out of scope. We could make C into a RAII object for R that invokes
release on destruction.
Basically now we have the situation where from the point of view of R and C (shallow resources), scope bound resource management alternatives functionally are fully equivalent to RAII. From a point of view of A and B (deep resources) however, we see a difference in the transitivity of “being a resource” emerging. With C as a RAII object, the interface and implementation of A, B and any code using a scoped A or B will remain unchanged and unaware of the newly introduced existence of “deep” resources. Without RAII however, the fact that C holds R means that C will need its own
release method for proxying the
release of R. B will now need its own
releasemethod for proxying the release of C. A will need its own
release method for proxying the release of B, and the scope where either A or B is used will also require of the alternative resource management techniques, where with RAII C provides the abstraction barrier that hides the implementation detail of “implemented using a resource” from the view of A, B and any users of an A or B. This difference shows that RAII effectively breaks the compositional transitivity of the “being a resource” property.