11 August 2012

RAII: Resource acquisition is initialization

Hello, dear reader. After reviewing my previous post about exception handling many people advised me to write about RAII either. As the latter is not C++-specific only and it actually does not much relate to exception handling I decided to write about it in a separate post. So What is RAII?

RAII stands for Resource Acquisition Is Initialization. It is a programming technique invented by Bjarne  Stroustrup and intended to make the usage of resources more safe in terms of their allocation and deallocation. In C++ after an exception is thrown during program execution the only thing that the standard guarantees to be executed is the destructors of automatic objects allocated on the stack (the destructors of objects with static storage duration are also called and all this is done in std::exit() function which also calls user-defined functions registered with std::atexit(), though these are not the case for RAII). So if we want to allocate a resource to use it somehow, RAII implies its allocation in a class constructor, and deallocation in the destructor. Thus, if anything goes wrong, we can be sure that the resource will be deallocated properly. Let's try this on a simple example.

The most common example used through the literature is the file resource, e.g. a handle of the opened file stream, we also can give this example here, as it does not change the essence. Suppose we need to open an xml file, read some structured data in portions (3 high-level items at a time), process it (e.g. convert to another format, or just deserialize an object from the xml file), and finally close the file. Here is a code snippet for the function which covers all the steps:

MyClass LoadFromXMLFile(const std::string& filePath)
{
       // Create an empty object
       MyClass obj;

       // Open a stream to read from xml file
       std::ifstream in(filePath, std::ios_base::in);

       // Read data in small chunks and fill the object
       FillObjectDataFromStream(obj, in);

       // Close the stream
       in.close();

       // Return the object
       return obj;
}

The dangerous part of this function is FillObjectDataFromStream() function. If it throws an exception the file stream will never be closed (not talking about process termination). So this means that we do not release a resource which is not used already and that is very bad practice.

Now if we want to take advantage of the RAII technique we need a helper class, which will allocate the resource in the constructor and release it in the destructor. Let's name this class FileStreamOpener:

class FileStreamOpener
{
private:
       std::ifstream _in;

public:
       FileStreamOpener(const std::string& filePath)
       {
              _in.open(filePath.c_str(), std::ios_base::in);
       }

       ~FileStreamOpener()
       {
              _in.close();
       }

       std::ifstream& GetStream()
       {
              return _in;
       }
};

Now we need to modify LoadFromXMLFile() function, here we go:

MyClass LoadFromXMLFile(const std::string& filePath)
{
       // Create an object
       MyClass obj;

       // Implicitly open a stream through FileStreamOpener
       FileStreamOpener fso(filePath);

       // Read data in small chunks and fill the object
       FillObjectDataFromStream(obj, fso.GetStream());

       // We don't even need to close the stream
       // as fso will be destructed when the flow
       // goes out of this function's body scope
       // and the stream will be closed.
       return obj;
}

The details are given in comments. Now whenever the destructor of 'fso' object is called, more precisely, during stack unwinding if exception is thrown or after the execution flow leaves the function body scope, the file stream will be closed, i.e. the resource will be properly released. This is the whole idea of the RAII idiom. Thanks for your time.

2 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Never seen such a practical and proper explanation.......Thanks.....Please write about all design patterns and and how to identify them and apply them....When such a simple explanation is given I personally feel your
    moving a section of software engineers to next level....

    ReplyDelete