×

Search anything:

RAII in C++

C++

Binary Tree book by OpenGenus

Open-Source Internship opportunity by OpenGenus for programmers. Apply now.

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:

  1. The resource is obtained using the constructor().
  2. The resource is released in the destructor.
  3. The class's instances are allocated to the stack.

Properties :

  1. Object should be in ready state .
  2. 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

  1. Helpful for managing thread locks in multi-threaded applications
  2. Helpful for controlling file access during operations.
  3. To provide safety from exceptions
  4. To prevent resource leaks without utilising try/catch blocks extensively.
  5. 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:

  1. Smart pointer is an abstract data type .
  2. 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 :

  1. Resources are available to all functions that access the object
  2. Resources are only released when an object's lifespan comes to an end and user dont need to release them explicitly.
  3. 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++ ?

Resource Allocation Is Initialization
Resource Acquisition Is Initialization.
Resource Acquisition Initialization
Resource Acquisition Is Implemented.
RAII stands for Resource Acquisition Is Initialization. It is a approach for managing the lifespan of resources..

Question 2

which of the follwing is not application of RALL?

Useful to control thread locks in multi-threaded application
Useful in file operations to control files access.
To ensure exception safety
None of this
RALL is useful to control thread locks in multi-threaded application,file operations to control files access,To ensure exception safety,to avoid resource leaks without extensive use of try/catch blocks and to allocate memory dynamically.
RAII in C++
Share this