Did you already use RAII in C++?
RAII for "Resource Acquisition Is Initialization". Or SBRM for "Scope-Bound Resource Management". Or even “automatic variables”.
Behind those strange names, there is a powerful concept. It is an idiom which helps you to improve the scalability of your project. Let's review how to use it!
The problem - Memory allocation
First, let’s see one of the most famous developmental errors in C++: Not freed memory.
We can write a simple piece of code like this one:
C++ - Operation on pointer
class LargeObject { // ... Other stuff ... // private: std::vector<std::string> vectors; // ... Other stuff ... // }; int myFunction() { LargeObject *i = new LargeObject; int retValue = 0; // ... Do Some large operations ... // delete i; return retValue; }
Here, the memory is allocated and then deleted at the end of the scope. The developer manually deletes the object.
Let’s imagine that during years, this code evolves.
Then, one day, it looks like this:
C++ - Operation on pointers - Memory leak
class LargeObject { // ... Other stuff ... // private: std::vector<std::string> vectors; // ... Other stuff ... // }; int myFunction() { LargeObject *i = new LargeObject; int retValue = 0; bool condition = false; // ... Do Some large operations ... // if (condition == false) { return retValue; } // ... Do Some large operations ... // delete i; return retValue; }
During code maintenance, one developer forgot to delete the pointer. Then, a memory leak occurs at each call of this function.
This kind of pointers is hard to manage. Indeed, those pointers are encapsulated in classes, long functions, and depend on designs... Moreover, it can lead to multiple well-known security issues.
The fact is the lifetime of an object is not easy to manage. The declaration of the pointer, its content, and lifetime management are separated. All those concepts are the responsibility of the developer.
We are human, we make errors during development. A code review can help to detect those kinds of errors. However, what about a complex design?
RAII in C++ is a solution to this issue. What is RAII?
RAII (or “Resource Acquisition Is Initialization “) is a great process to mitigate the featured issue above.
This process guarantees an "automatic management" of the lifetime of an object. In RUST, RAII is managed by default to guarantee safe code.
In C++, the technique consists of “release” a resource on a "destructor call". This concept is present in some STL library components:
- std::lock_guard: Lock Guard is the perfect model of RAII. This wrapper will take a simple mutex as a parameter. Then, during "constructor call", the mutex is locked.
This mutex is automatically released during "destructor call"! It is a great protection against the deadlock issues! - std::fstream: Here, the file closes at the end of scope.
- std::unique_ptr and std::shared_ptr: In the "smart pointers" case, the resource is freed at the end of scope.
This is the RAII idiom. The object in the stack is responsible for a single resource. It can be a file, a mutex, or a pointer! Then, this resource is released during destruct time (End of scope, object destructor...). The lifetime of the contained object is automatically managed!
Go back to our problem. How to use RAII in C++.
As you see, RAII is perfect to manage a single resource during a single scope.
Now, let’s apply the RAII on our problematic C++ code with a simple “std::unique_ptr”!
C++ - RAII usage with unique pointers
#include <memory> class LargeObject { // ... Other stuff ... // private: std::vector<std::string> vectors; // ... Other stuff ... // }; int myFunction() { std::unique_ptr<LargeObject> i(new LargeObject); int retValue = 0; bool condition = false; // ... Do Some large operations ... // if (condition == false) { return retValue; } // ... Do Some large operations ... // return retValue; }
Now, thanks to the "unique_ptr" implementation, my allocated pointer is automatically released! A developer doesn’t need to destroy the resource manually.
You can use "unique_ptr" in C++11 with "#include <memory>".