At the end of scope, in C++, all the stack allocated objects will be destructed for sure, even exception is thrown. RAII Idiom makes use of this feature by wrapping the resource in a class. In constructor, resource would be allocated and in destructor, release would happen. This is exception-safe. This calls for cleaning up all the resources at single place, destructor, instead of sprinkling this logic everywhere.
Let me give a simple example to illustrate this concept using File Stream example. Consider a function which takes two arguments, a string and file name; Let us assume the functionality of this is to write the string into file. One may code as given below.
fstream stream;
stream.open(fileName, ios::binary | ios::out | ios::app);
if(stream.is_open())
{
stream << str; // Assume there is an exception here ...
}
stream.close();
If there is some exception thrown at some point while writing, stream.close() won't get called at all. One solution is to solve this is adding a try/ catch around the writing part, which may lead to unessential maintenance issues. Program wouldn't be easily readable also. Let us rewrite the same using RAII as below.
class SmartFile
{
public:
SmartFile(string fileName)
{
cout << "Stream Opening" << endl;
stream.open(fileName, ios::binary | ios::out | ios::app);
}
~SmartFile()
{
cout << "Stream Closing" << endl; stream.close();
}
void WriteString(string str)
{
if(stream.is_open())
{
cout << "File Writing" << endl; stream << str;
}
else
{
cout << "Write Error" << endl;
}
}
private:
fstream stream;
};
void WriteStringToFile(string str, string fileName)
{
SmartFile file(fileName);
file.WriteString(str);
}
The above function using RAII class SmartFile which is reliable, exception-safe. You can try the below given code to understand the same.
void WriteStringToFile(string str, string fileName)
{
SmartFile file(fileName);
throw 10;
file.WriteString(str);
}
Even though the above code throws an error code abnormally, SmartFile's destructor will be called.
RAII is being used in Smart Pointers, Synchronization based lock classes, etc. In a nutshell, this idiom necessitates to have all resources allocations in constructor and all deallocation logic in destructor to make the code exception-safe and maintainable.
Thanks for Reading.