Resource acquisition is initialization


Resource acquisition is initialization is a programming idiom used in several object-oriented, statically typed programming languages to describe a particular language behavior. In RAII, holding a resource is a class invariant, and is tied to object lifetime. Resource allocation is done during object creation, by the constructor, while resource deallocation is done during object destruction, by the destructor. In other words, resource acquisition must succeed for initialization to succeed. Thus, the resource is guaranteed to be held between when initialization finishes and finalization starts, and to be held only when the object is alive. Thus, if there are no object leaks, there are no resource leaks.
RAII is associated most prominently with C++, where it originated, but also Ada, Vala, and Rust. The technique was developed for exception-safe resource management in C++ during 1984–1989, primarily by Bjarne Stroustrup and Andrew Koenig, and the term itself was coined by Stroustrup.
Other names for this idiom include Constructor Acquires, Destructor Releases and one particular style of use is called Scope-based Resource Management. This latter term is for the special case of automatic variables. RAII ties resources to object lifetime, which may not coincide with entry and exit of a scope. However, using RAII for automatic variables is the most common use case.

C++ example

The following C++23 example demonstrates usage of RAII for file access and mutex locking:

import std;
using std::lock_guard;
using std::mutex;
using std::ofstream;
using std::runtime_error;
using std::string;
void writeToFile

This code is exception-safe because C++ guarantees that all objects with automatic storage duration are destroyed at the end of the enclosing scope in the reverse order of their construction.
The destructors of both the lock and file objects are therefore guaranteed to be called when returning from the function, whether an exception has been thrown or not.
Local variables allow easy management of multiple resources within a single function: they are destroyed in the reverse order of their construction, and an object is destroyed only if fully constructed—that is, if no exception propagates from its constructor.
Using RAII greatly simplifies resource management, reduces overall code size and helps ensure program correctness. RAII is therefore recommended by industry-standard guidelines,
and most of the C++ standard library follows the idiom.

Benefits

The advantages of RAII as a resource management technique are that it provides encapsulation, exception safety, and locality.
Encapsulation is provided because resource management logic is defined once in the class, not at each call site. Exception safety is provided for stack resources by tying the resource to the lifetime of a stack variable : if an exception is thrown, and proper exception handling is in place, the only code that will be executed when exiting the current scope are the destructors of objects declared in that scope. Finally, locality of definition is provided by writing the constructor and destructor definitions next to each other in the class definition.
Resource management therefore needs to be tied to the lifespan of suitable objects in order to gain automatic allocation and reclamation. Resources are acquired during initialization, when there is no chance of them being used before they are available, and released with the destruction of the same objects, which is guaranteed to take place even in case of errors.
Comparing RAII with the finally construct used in Java, Stroustrup wrote that “In realistic systems, there are far more resource acquisitions than kinds of resources, so the 'resource acquisition is initialization' technique leads to less code than use of a 'finally' construct.”
As a class invariant, RAII provides guarantees that an object instance that is supposed to have acquired a resource has in fact done so. This eliminates the need for additional "setup" methods to get a newly-created object into a usable state, and the need to test instances to verify that they have been properly set up before every use.

Typical uses

The RAII design 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 execution leaves the scope of the RAII object.
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 execution leaves the object's scope. In both cases, RAII ensures only 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.
Ownership of dynamically allocated objects can also be controlled with RAII, such that the object is released when the RAII object is destroyed. For this purpose, the C++11 standard library defines the smart pointer classes std::unique_ptr for single-owned objects and std::shared_ptr for objects with shared ownership. Similar classes are also available through std::auto_ptr in C++98, and boost::shared_ptr in the Boost libraries.
Also, messages can be sent to network resources using RAII. In this case, the RAII object would send a message to a socket at the end of the constructor, when its initialization is completed. It would also send a message at the beginning of the destructor, when the object is about to be destroyed. Such a construct might be used in a client object to establish a connection with a server running in another process.

Compiler "cleanup" extensions

Both Clang and the GNU Compiler Collection implement a non-standard extension to the C language to support RAII: the "cleanup" variable attribute. The following annotates a variable with a given destructor function that it will call when the variable goes out of scope:

void example_usage

In this example, the compiler arranges for the fclosep function to be called on logfile before example_usage returns.

Limitations

RAII only works for resources acquired and released by stack-allocated objects,
where there is a well-defined static object lifetime.
Heap-allocated objects which themselves acquire and release resources are common in many languages, including C++. RAII depends on heap-based objects to be implicitly or explicitly deleted along all possible execution paths, in order to trigger its resource-releasing destructor. This can be achieved by using smart pointers to manage all heap objects, with weak pointers for cyclically referenced objects.
In C++, stack unwinding is only guaranteed to occur if the exception is caught somewhere. This is because "If no matching handler is found in a program, the function terminate is called; whether or not the stack is unwound before this call to terminate is implementation-defined.". This behavior is usually acceptable, since the operating system releases remaining resources like memory, files, sockets, etc. at program termination.
At the 2018 Gamelab conference, Jonathan Blow claimed that use of RAII can cause memory fragmentation which in turn can cause cache misses and a 100 times or worse hit on performance.