Raii
Raii
Raii
Language support
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.
Typical uses
The RAII technique is often used for controlling mutex locks in multi-threaded applications. In that use, the object
releases the lock when destroyed. Without RAII in this scenario the potential for deadlock would be high and the
logic to lock the mutex would be far from the logic to unlock it. With RAII, the code that locks the mutex essentially
includes the logic that the lock will be released when the RAII object goes out of scope. Another typical example is
interacting with files: We could have an object that represents a file that is open for writing, wherein the file is
opened in the constructor and closed when the object goes out of scope. In both cases, 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.
The ownership of dynamically allocated memory (such as memory allocated with new in C++ code) can be
controlled with RAII, such that the memory is released when the RAII object is destroyed. For this purpose, the C++
Standard Library defines the smart pointer class std::auto_ptr that is deprecated in C++11 in favor of std::unique_ptr.
Furthermore, smart pointer with shared-ownership semantics such as tr1::shared_ptr (defined in C++ by
TR1 and marked for inclusion in the current C++11 standard), or policy based smart pointers such as
Loki::SmartPtr (from Loki), can also be used to manage the lifetime of shared objects.
Resource Acquisition Is Initialization 2
C++ example
The following RAII class is a lightweight wrapper of the C standard library file system calls.
#include <cstdio>
#include <stdexcept> // std::runtime_error
class file {
public:
file(const char* filename)
: file_(std::fopen(filename, "w+")) {
if (!file_) {
throw std::runtime_error("file open failure");
}
}
~file() {
if (std::fclose(file_)) {
// failed to flush latest changes.
// handle it
}
}
private:
std::FILE* file_;
void example_usage() {
file logfile("logfile.txt"); // open file (acquire resource)
logfile.write("hello logfile!");
// continue using logfile ...
// throw exceptions or return without
// worrying about closing the log;
// it is closed automatically when
// logfile goes out of scope
}
This works because the class file encapsulates the management of the FILE* file handle. When file objects
are local to a function, C++ guarantees that they are destroyed at the end of the enclosing scope (the function in the
Resource Acquisition Is Initialization 3
example), and the file destructor releases the file by calling std::fclose(file_). Furthermore, file
instances guarantee that a file is available by throwing an exception if the file could not be opened when creating the
object.
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.
Using RAII-enabled resources simplifies and reduces overall code size and helps ensure program correctness.
#define RAII_VARIABLE(vartype,varname,initval,dtor) \
void _dtor_ ## varname (vartype * v) { dtor(*v); } \
vartype varname __attribute__((cleanup(_dtor_ ## varname))) =
(initval)
void example_usage() {
RAII_VARIABLE(FILE*, logfile, fopen("logfile.txt", "w+"), fclose);
fputs("hello logfile!", logfile);
}
In this example, the compiler arranges for the fclose() function to be called before example_usage() returns.
Finalizers
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 the dispose pattern.
In Java versions prior to Java 7, the preceding example would be written like this:
class JavaExample {
void exampleMethod() {
// open file (acquire resource)
final LogFile logfile = new LogFile("logfile.txt");
Resource Acquisition Is Initialization 4
try {
logfile.write("hello logfile!");
In Java 7 and later, using the new try-with-resources construct, this pattern can be declared a bit more concisely (but
is still essentially equivalent to the above code, assuming no exceptions are thrown by the close() method):
class JavaExample {
void exampleMethod() {
// open file (acquire resource)
try (LogFile logfile = new LogFile("logfile.txt")) {
logfile.write("hello logfile!");
In both cases, the burden of releasing resources falls on the programmer each time a resource is used: The
programmer must either explicitly write finally blocks, or must remember to construct the object in the
"try-with-resources" construct in order to ensure that the resource is released.
Note, however, that at least one of the benefits of RAII-style coding is still applicable to Java: Construction and
initialization can be tightly coupled. For instance, in the above examples, note that it is impossible for code to refer
to the variable logfile before it points to a valid object, since the variable logfile is declared explicitly
final in the first example (and is implicitly final in the second due to the semantics of the try-with-resources
construct) and that in both cases it is initialized on the same line as it is declared, with a new expression that both
creates and initializes the object it will reference.
Resource Acquisition Is Initialization 5
Closure blocks
Ruby and Smalltalk do not support RAII, but have a pattern that makes use of methods that pass resources to closure
blocks. Here is an example in Ruby:
The open method ensures that the file handle is closed without special precautions by the code writing to the file.
This is similar to Common Lisp's 'unwind-protect' [3]-based macros:
Python's with statement [4] and the using statement in C# and Visual Basic 2005 are also similar and provide
deterministic resource management within a block and do away with the requirement for explicit finally-based
cleanup and release.
In C#, this is accomplished by wrapping any object that implements the IDisposable interface in a using
statement. When execution leaves the scope of the using statement body, the Dispose method on the wrapped
object is executed giving it a deterministic way to clean up any resources.
Reference counting
Perl and CPython[5] manage object lifetime by reference counting, making it possible to use RAII in a limited form.
Objects that are no longer referenced are immediately released, so a destructor can release the resource at that time.
However, object lifetime isn't necessarily bound to any lexical scope. One can store a reference to an object in a
global variable, for example, thus keeping the object (and resource) alive indeterminately long. This makes it
possible to accidentally leak resources that should have been released at the end of some scope. Also, in the case of
Resource Acquisition Is Initialization 6
Python, the actual garbage collection strategy is an implementation detail, and running with an alternative interpreter
(such as IronPython or Jython) could result in the RAII implementation not working.
Ad-hoc mechanisms
Languages with no direct support for defining constructors and destructors sometimes still have the ability to support
ad-hoc RAII methods using programmer idioms. C, for example, lacks direct support for these features, yet
programming languages with such support are often implemented in C, and fragile support can be achieved in C
itself, although at the cost of additional cognitive overhead on the part of the programmer.
The lack of any standardized idiom for dynamic object allocation beyond malloc and free can be addressed
numerous ways, such as through a programming idiom of having TNew, TDelete, and Tmethod functions for any
given type T. The ability of throw to do non-local jumps can be simulated under Unix with the setjmp/longjmp
library functions, and the syntactic sugar needed to make the result readable can be injected using the C
preprocessor. A C compiler supporting variadic macros and in-expression variable declarations, like gcc, makes code
like the following possible - although needing to go outside of C proper (the macros are actually textual substitutions
performed by the preprocessor) causing difficulty both in maintenance and especially in interpreting debugger
results.
#include <stdio.h>
#include <malloc.h>
#include <setjmp.h>
There are many different, often partial, solutions to the problem, such as handling object cleanup with goto[6] , code
that creates objects for the exceptions,[7] or addresses multithreading issues.[8] The real weakness of not having direct
language support for RAII features is in situations where code from multiple sources is being combined, and all the
ad-hoc methods being used fail to interact properly, or worse yet, directly conflict with each other.
Additionally, in languages where the common idiom doesn't include exceptions, there can be significant resistance
from the entrenched community to write code like the example above, instead of the superficially more compact, but
unscalable, code below which implements the same basic function and error checking but without RAII or
exceptions.
#include <stdio.h>
#include <string.h>
int main(int ac, char **av) {
int succp = 0;
FILE *from = 0, *to = 0;
if(from = fopen("file-from", "r+")) {
if(to = fopen("file-to", "w")) {
int c;
while(EOF != (c = fgetc(from))) {
if(EOF == fputc(c, to)) {
perror("fputc");
break;
}
}
puts("copy complete"), succp = 1;
if(EOF == fclose(to)) perror("fclose -to-");
} else {
perror("fopen -to-");
}
if(EOF == fclose(from)) perror("fclose -from-");
} else {
perror("fopen -from-");
}
return succp ? 0 : -1;
}
In such code, only block structure retains the shadow of RAII, and error handling now dominates the main function,
error output must now be interpreted by the user rather than providing convenient catch hooks. Further, if the same
style were converted to library code, those functions would now be rife with uninternationalized text strings. All of
these factors tend to inhibit the implementation of sufficient error handling by programmers; it is common to ignore
return values from fputc, and fclose, in particular, despite the fact that the failure of fputc could be due to a
filesystem being full, and proceeding blithely could result in catastrophic data loss (a problem once exhibited by the
compress program, leading to undesired, 100% file compression).
Resource Acquisition Is Initialization 9
The biggest problem with ad-hoc mechanisms, even for projects where mixing with other ad-hoc approaches can be
obviated, is one of questionable code resilience. Ad-hocs are typically specific to individual projects, and usually
haven't been subjected to the same rigorous testing and code review that RAII and exception mechanisms are when
supported as a primary language feature. It's far more reasonable for a team to base the success of a important project
on the exception handling of an internationally supported C++ compiler, than to rely on an ad-hoc C mechanism
such as the example provided above, and usually even preferable to mechanisms constructed in house by the same
team.
References
[1] Stroustrup, Bjarne (1994). The Design and Evolution of C++. Addison-Wesley. ISBN 0-201-54330-3.
[2] http:/ / gcc. gnu. org/ onlinedocs/ gcc/ Variable-Attributes. html
[3] http:/ / www. lispworks. com/ documentation/ HyperSpec/ Body/ s_unwind. htm
[4] http:/ / www. python. org/ dev/ peps/ pep-0343/
[5] Python 2.5.2 manual: 1.10 Reference Counts (http:/ / www. python. org/ doc/ 2. 5. 2/ ext/ refcounts. html) Accessed on 2009-05-15.
[6] CERT MEM12-C. Consider using a Goto-Chain when leaving a function on error when using and releasing resources (https:/ / www.
securecoding. cert. org/ confluence/ display/ seccode/ MEM12-C. + Consider+ using+ a+ Goto-Chain+ when+ leaving+ a+ function+ on+
error+ when+ using+ and+ releasing+ resources?rootCommentId=29033072#comments)
[7] Exceptions in C (http:/ / adomas. org/ excc/ )
[8] Exception Handling in C without C++ (http:/ / www. on-time. com/ ddj0011. htm)
External links
• Sample Chapter " Gotcha #67: Failure to Employ Resource Acquisition Is Initialization (http://www.informit.
com/articles/article.aspx?p=30642&seqNum=8)" by Stephen Dewhurst
• Interview " A Conversation with Bjarne Stroustrup (http://artima.com/intv/modern3.html)" by Bill Venners
• Article " The Law of The Big Two (http://artima.com/cppsource/bigtwo3.html)" by Bjorn Karlsson and
Matthew Wilson
• Article " Implementing the 'Resource Acquisition is Initialization' Idiom (http://web.archive.org/web/
20080129235233/http://gethelp.devx.com/techtips/cpp_pro/10min/2001/november/10min1101.asp)" by
Danny Kalev
• Article " RAII, Dynamic Objects, and Factories in C++ (http://www.codeproject.com/KB/cpp/RAIIFactory.
aspx)" by Roland Pibinger
• Article " Managing Dynamic Objects in C++ (http://www.ddj.com/184409895)" by Tom Cargill
• Blog Entry " RAII in C++ (http://jrdodds.blogs.com/blog/2004/08/raii_in_c.html)" by Jonathan Dodds
Article Sources and Contributors 10
License
Creative Commons Attribution-Share Alike 3.0 Unported
//creativecommons.org/licenses/by-sa/3.0/