RAII in C++
In C++ programming, we have a secure and safe resource management technique known as RAII. RAII is an acronym for "Resource Acquisition Is Initialization". We use this approach in many programming languages, such as C++, Rust, Vala, and Ada. It was primarily originated for C++ by Bjarne Stroustrup and Andrew Koenig. Generally, RAII is called an initialism or "R A double I". In this article, we will thoroughly discuss the introduction to raii, the need for raii, problems solved with the help of raii and some examples of RAII in C++ programming.
Garbage collection is a mechanism where resources and memory must be released and managed safely. Many languages, like, Java, have automatic garbage collection. In C++, we do not have automated garbage collection. Here the programmer himself has to manage the heap memory release and other memory management processes. In C++ programming, the program should be executed such that it returns the resources to the operating system. The leak may occur if the program fails to release the unused resource. Due to the leak, the unused resources not released by the program are isolated and can only be used by other programs once the process is completed. The most common problem or bug is memory leak, which makes programming in C/C++ more difficult.
In the modern version of C++, they avoid memory management with heap as much as possible. Here the approach of object declaration using stack is used. In a scenario when the resource is considered too big for the stack, the resource is then owned by the object. After the programmer initializes the object, it is acquired by the resource owned by the object. The object in its destructor then releases the resource. In simple terms, the object is responsible for managing the resources. The mechanism where the objects own the resources is called RAII (Resource Acquisition Is Initialization).
RAII is related to the life cycle of the resource owned by the object. RAII helps manage memory resources and sockets, files, and locks. The need and usage of RAII go beyond the garbage collector, which only manages the memory. RAII is a class variant containing the entire life cycle of the resource. After the programmer initializes the object, the object should own or acquire the resources with the help of the constructor. Next, when the process is over and the object is not running in the scope, it should release all the resources. The object removes all these resources with the help of a destructor.
Now we understand the need and usage of RAII (Resource Acquisition Is Initialization). So, let us know more about RAII using some examples given in the below section.
Example1:
// C++ program to demonstrate the concept of RAII (Resource Acquisition Is Initialization)
#include <iostream>
class memory_management {
public:
memory_management(size_t size) : size_(size), data_(new int[size]) {
std::cout << "The allocated size of the memory block is: "
<< size_ << std::endl;
}
~memory_management() {
std::cout << "The allocated size of the memory block is: "
<< size_ << std::endl;
delete[] data_;
}
int* data() const {
return data_;
}
size_t size() const {
return size_;
}
private:
size_t size_;
int* data_;
};
int main() {
{
memory_management block(20);
}
//, Here the destructor is called since the object is now out of the scope
//Now the memory should be released
std::cout << "Execution of the program has been successfull" << std::endl;
return 0;
}
Output
![RAII in C++](https://static.tutorialandexample.com/cpp/raii-in-cpp1.png)
Explanation
Here, we have taken a simple example which illustrates the use of RAII in C++ programming. Using this technique, we can easily avoid problems of memory leaks. In the above program, we have defined a class named memory management. The class memory_management has a constructor that takes the memory block's size in its argument.
The constructor also allocates the new memory for the object using data_(new int[size]. It then also prints the allocated and deallocated memory size for the object. As we know, in RAII, we have a destructor which releases the memory. Here we have a destructor named delete[] date, which deallocates or frees the memory. After that, we have our driver or main function inside, creating a new block for the memory management class. After the execution of the process is completed and it goes outside the scope, the delete[] date, which is the destructor, is called, and the memory is released.
Example2:
In the below example, we have an object, e. The object is initialized and then destroyed at the end of the function block. The given object e does not have its resources. Its members are initialized on the stack. s and its object go out as soon as the function scope ends.
// C++ program to demonstrate the concept of RAII (Resource Acquisition Is Initialization)
class example {
private:
shape s; // associated with the lifecycle of an object
public:
void draw();
};
void exampleFunction () {
example e; // associated with the lifecycle of an object with scope
// constructs w, including the w.g gadget member
// ...
e.draw();
// ...
} // automatic destruction and deallocation for e and e.g
// provides exception safety
Example3:
In this example, the object w owns its resource. Thus we must define the destructor so it deallocates the memory, unlike in the previous example, where there was no need to write extra code.
class example
{
private:
int* data;
public:
example(const int size) {
data = new int[size];
}
~example() {
delete[] data;
}
void do_something() {}
};
void exampleFunction() {
example e(2000000);
e.do_something();
} // automatic destruction and deallocation for e and e.data
Smart Pointers
Since C++ 11, there is an efficient way which helps us in RAII (Resource Acquisition Is Initialization) and minimizes the memory leak issue. Smart pointer helps in the automatic management of memory. It eliminates the need for an explicit destructor, as we have used in the previous example. Smart pointers help make a standard pointer usable for memory management, networks, files and connections.
Below is an example of using smart pointers for memory allocation and deallocation.
#include <memory>
class example
{
private:
std::unique_ptr<int[]> data;
public:
example(const int size) {
data = std::make_unique<int[]>(size);
}
void do_something() {
}
};
void functionUsingWidget() {
example e(2000000);
e.do_something();
// ...
} // automatic destruction and deallocation for e and e.data