What is meant by Resource Acquisition is Initialization (RAII)?
Manual memory management is a nightmare that programmers have been inventing ways to avoid since the invention of the compiler. Programming languages with garbage collectors make life easier, but at the cost of performance. In this article - Eliminating the Garbage Collector: The RAII Way, Toptal engineer Peter Goodspeed-Niklaus gives us a peek into the history of garbage collectors and explains how notions of ownership and borrowing can help eliminate garbage collectors without compromising their safety guarantees.
There are three parts to an RAII class:
RAII stands for "Resource Acquisition is initialization." The "resource acquisition" part of RAII is where you begin something that must be ended later, such as:
The "is initialization" part means that the acquisition happens inside the constructor of a class.
https://www.tomdalling.com/blog/software-design/resource-acquisition-is-initialisation-raii-explained/
"RAII" stands for "Resource Acquisition is Initialization" and is actually quite a misnomer, since it isn't resource acquisition (and the initialization of an object) it is concerned with, but releasing the resource (by means of destruction of an object).
But RAII is the name we got and it sticks.
At its very heart, the idiom features encapsulating resources (chunks of memory, open files, unlocked mutexes, you-name-it) in local, automatic objects, and having the destructor of that object releasing the resource when the object is destroyed at the end of the scope it belongs to:
{
raii obj(acquire_resource());
// ...
} // obj's dtor will call release_resource()
Of course, objects aren't always local, automatic objects. They could be members of a class, too:
class something {
private:
raii obj_; // will live and die with instances of the class
// ...
};
If such objects manage memory, they are often called "smart pointers".
There are many variations of this. For example, in the first code snippets the question arises what would happen if someone wanted to copy obj
. The easiest way out would be to simply disallow copying. std::unique_ptr<>
, a smart pointer to be part of the standard library as featured by the next C++ standard, does this.
Another such smart pointer, std::shared_ptr
features "shared ownership" of the resource (a dynamically allocated object) it holds. That is, it can freely be copied and all copies refer to the same object. The smart pointer keeps track of how many copies refer to the same object and will delete it when the last one is being destroyed.
A third variant is featured by std::auto_ptr
which implements a kind of move-semantics: An object is owned by only one pointer, and attempting to copy an object will result (through syntax hackery) in transferring ownership of the object to the target of the copy operation.
RAII concept is just a C stack variable idea. the simplest way to explain.
It's a really terrible name for an incredibly powerful concept, and perhaps one of the number 1 things that C++ developers miss when they switch to other languages. There has been a bit of a movement to try to rename this concept as Scope-Bound Resource Management, though it doesn't seem to have caught on just yet.
When we say 'Resource' we don't just mean memory - it could be file handles, network sockets, database handles, GDI objects... In short, things that we have a finite supply of and so we need to be able to control their usage. The 'Scope-bound' aspect means that the lifetime of the object is bound to the scope of a variable, so when the variable goes out of scope then the destructor will release the resource. A very useful property of this is that it makes for greater exception-safety. For instance, compare this:
RawResourceHandle* handle=createNewResource();
handle->performInvalidOperation(); // Oops, throws exception
...
deleteResource(handle); // oh dear, never gets called so the resource leaks
With the RAII one
class ManagedResourceHandle {
public:
ManagedResourceHandle(RawResourceHandle* rawHandle_) : rawHandle(rawHandle_) {};
~ManagedResourceHandle() {delete rawHandle; }
... // omitted operator*, etc
private:
RawResourceHandle* rawHandle;
};
ManagedResourceHandle handle(createNewResource());
handle->performInvalidOperation();
In this latter case, when the exception is thrown and the stack is unwound, the local variables are destroyed which ensures that our resource is cleaned up and doesn't leak.
The book C++ Programming with Design Patterns Revealed describes RAII as:
Where
Resources are implemented as classes, and all pointers have class wrappers around them (making them smart pointers).
Resources are acquired by invoking their constructors and released implicitly (in reverse order of acquiring) by invoking their destructors.