RAII in C++
Do not miss this exclusive book on Binary Tree Problems. Get it now for free.
In this article, we will discuss RAII or Resource Acquisition Is Initialization approach in C++ with help of an example.
Table of Contents :
- Introduction To RAII
- Introduction To Resource
- Rall class Properties
- Example With Explanation
- Implementation of RAII in Standard Library
- Application Of RAII
- Introduction To Smart Pointer
- Example of smart pointer
- Conclusion
- Quiz
Introduction To RAII
In c++, RAII stands for " Resource Acquisition Is Initialization ". also known as "Scope-Bound Resource Management".It is a approach for managing the lifespan of resources.
Before moving to the concept of RALL ,lets first understand what is resource.
Resource :
Resource are limited supply which must be obtained before use.It can be allocate/acquire and deallcoate/release.
Example : heap memory,file handles, network sockets, mutexes,database sessions & transactions etc.
Resource leak :
Resource Leaks occur when unused resources are not released. All acquired resources must be returned to the operating system by each resource.
If resources are not freed, other programs cannot access them, which may lead to software bugs.
Resource Allocation and deallcoation :
Resource Type | Acquire | Release |
---|---|---|
Memory | new | delete |
Sockets | sockets | close |
Files | fopen | fclose |
Locks | try_lock | unlock |
RALL:
RAII is a class variation that is associated to life of object. Whenever you initialize an object, it should already acquired resources using constructor.
and When an object goes out of scope, it should release every acquired resource with the help of destructor.
Additionally, it never raises an exception.
An RAII class is divided into three sections:
- The resource is obtained using the constructor().
- The resource is released in the destructor.
- The class's instances are allocated to the stack.
Properties :
- Object should be in ready state .
- Object should not partially ready or partially dead.
3 .Use the resource only through an instance of a RAII-class that has automatic storage duration or has temporary lifetime of its own.
RAII ties together a resource's life cycle, which must be obtained before usage, as follows:
- heap memory allocation
- execution of thread
- open socket & file
- locked mutex
- disk space
- database connection
anything which is available as long as the object exists in life cycle.
As we already learned RALL is useful in file operations to control files access.
let's see an example where input file stream is opened in the objects constructor and automatically get closed destruction of the object.
Example 1:
//c program to implement RALL approach
#include <cstdio>
// exceptions
class file_error { } ;
class open_error : public file_error { } ;
class close_error : public file_error { } ;
class write_error : public file_error { } ;
//create class
class file
{
public:
file( const char* filename )
:
m_file_handle(std::fopen(filename, "w+"))
{
//check file is present or not
if( m_file_handle == NULL )
{
//throw exception
throw open_error() ;
}
}
//constructor
~file()
{
std::fclose(m_file_handle) ;
}
void write( const char* str )
{
if( std::fputs(str, m_file_handle) == EOF )
{
throw write_error() ;
}
}
void write( const char* buffer, std::size_t num_chars )
{
if( num_chars != 0 && std::fwrite(buffer, num_chars, 1, m_file_handle) == 0 )
{
throw write_error() ;
}
}
private:
std::FILE* m_file_handle ;
file( const file & ) ;
file & operator=( const file & ) ;
} ;
void example()
{
file logfile("sample.txt") ;
logfile.write("Hello World!") ;
}
Output :
Hello World
Explanation
Here ,when sample.txt file opens it allocate resouce and write data inside file and automatically get closed because file destructor is called when function returns or throws an exception.
Lets take another example .
Example 2 :
//example vector
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v = { 7, 5, 16, 8 };
v.push_back(25);
v.push_back(13);
std::cout << "v = { ";
for (int n : v) {
std::cout << n << ", ";
}
std::cout << "}; \n";
}
Output:
v = { 7, 5, 16, 8, 25, 13, };
Explanation
Here, the vector is the handle object of its elements.The vector allocates heap space for its elements with new and frees that space with delete.By using vector you are unconcerned about the implementation details and will rely on the vector not to leak.
Example 3:
// File stream
#include <iostream>
#include <fstream>
using std::cout;
using std::cin;
using std::ofstream;
using std::ifstream;
using std::endl;
int main(void)
{
std::ofstream outFile("out.txt");
outFile << "Hello World\n";
std::ifstream inFile("in.txt");
int a;
inFile >> a;
cout << "closes the files" << endl;
return 0;
}
output :
closes the files
Out.txt file
Hello World
Explanation
Here, Destructor of outFile/inFile automatically closes the files .
ifstream will open the file and write some data inside file out.txt.
When an ifstream is no longer in scope, its destructor closes the file.
It is not necessary to use the.close() method.
Implementation of RAII in Standard Library
Type | Standard Library |
---|---|
Dynamic array | std::vector |
File | std::ifstream / std::ofstream |
Mutex | std::lock_guard |
Thread | std::jthread |
Pointer to heap | std::unique_point |
Application
- Helpful for managing thread locks in multi-threaded applications
- Helpful for controlling file access during operations.
- To provide safety from exceptions
- To prevent resource leaks without utilising try/catch blocks extensively.
- To dynamically allocate memory.
Problem statement
- To acquire resource we call New
- To release resources we call Delete.
But this is not automatically done when the pointers go out of scope.
void rawPtrFn()
{
//acquire memory
Node* n = new Node;
//delete memory
delete n;
}
if forget to release resource , we leak resource .
What would be an RAII solution to this?
Smart Pointer :
The Standard Library in modern C++ programming includes smart pointers, which are used to assist ensure that programs are free of memory and resource leaks and are exception-safe.
Additionally, C++ already has built-in smart pointers.
it contains
- weak _ptr
- auto ptr
- shared _ptr
- unique _ptr.
For memory management activities like handling files, network sockets, etc., smart pointers are utilized. Additionally, it is capable of carrying out several operations, including reference counting and automatic destruction.
Properties:
- Smart pointer is an abstract data type .
- Smart pointer implemented as template class
Example
#include <iostream>
using namespace std;
template <class T>
class Smartpointer
{
//Actual pointer
T *p;
public:
// Constructor of class
Smartpointer(T *ptr = NULL)
{
p = ptr;
}
// Destructor of class
~Smartpointer()
{
delete(p);
}
// Overloading de-referencing operator
T & operator * ()
{
return *p;
}
// Over loading arrow operator
T * operator -> ()
{
return p;
}
};
int main()
{
Smartpointer<int> p(new int());
*p = 10;
cout << "Pointer Value : "<<*p;
return 0;
}
Output :
Pointer Value : 10
Explanation
In this example, we have implemeted smartponter class with templeate class that includes a destructor, pointer, and overloaded operators like * and ->.The dynamically allocated memory would automatically be destroyed because the destructor is automatically invoked when an object exits scope. and the value of pointer get printed .
Conclusion :
- Resources are available to all functions that access the object
- Resources are only released when an object's lifespan comes to an end and user dont need to release them explicitly.
- When an object left its range of effect, the resource is automatically freed or released.
LETS CHECK YOUR KNOWELDGE :
Question 1
what is RALL in C++ ?
Question 2
which of the follwing is not application of RALL?
Sign up for FREE 3 months of Amazon Music. YOU MUST NOT MISS.