Skip to main content

RAII and Smart Pointers - Resource Management in C++

RAII stands for Resource Acquisition Is Initialization.

What is it and why it is needed?
We used different resource in out software such as file streams, network pipes, database connections and even locks are considered as resources.
The standardized procedure of using a resource is to acquire the resource, use it and then release it. Holding onto resources is bad practice and starves other processes for resources slowing down the entire system in multicore systems.

OK, what's the big deal?
So we want to open a file, write some stuff to it and then close it.
We just do.

file.open();
file.write("test");
file.close();

Caution here. If it's a trivial task where you don't have anything in between opening and closing the file (or any other resource) this seems fine but this is often not the case. You have many other things that you do between you opening the file and closing the file. Chances are these operations might fail, or worse throw.
In such case the programmers must ensure that they release their resources promptly even when throwing is expected. Java users can example use 'finally clause' after the try-catch blocks but in high performance systems handling exceptions is usually disregarded and there's nothing the programmer can do but to ensure that he frees his resources and continue other work.
Otherwise this would lead to memory leaks. Further what if a lock is not freed in such a situation>
This would surely cause the program to stall because of a deadlock.

Example usage of RAII idiom

//  Private copy constructor and copy assignment ensure classes derived 
//  from class NonCopyable cannot be copied.
class NonCopyable 
{
   NonCopyable (NonCopyable const &); // private copy constructor
   NonCopyable & operator = (NonCopyable const &); // private assignment operator
};
template <class T>
class AutoDelete : NonCopyable
{
  public:
    AutoDelete (T * p = 0) : ptr_(p) {}
    ~AutoDelete () throw() { delete ptr_; } 
  private:
    T *ptr_;
};
 
class ScopedLock : NonCopyable// Scoped Lock idiom
{
  public:
    ScopedLock (Lock & l) : lock_(l) { lock_.acquire(); }
    ~ScopedLock () throw () { lock_.release(); } 
  private:
    Lock& lock_;
};
 
void foo ()
{
  X * p = new X;
  AutoDelete<X> safe_del(p); // Memory will not leak
  p = 0;
  // Although, above assignment "p = 0" is not necessary
  // as we would not have a dangling pointer in this example. 
  // It is a good programming practice.
 
  if (...)
    if (...)
      return; 
 
  // No need to call delete here.
  // Destructor of safe_del will delete memory
}
void X::bar()
{
  ScopedLock safe_lock(l); // Lock will be released certainly
  if (...)
    if (...)
      throw "ERROR"; 
  // No need to call release here.
  // Destructor of safe_lock will release the lock
}
 
Things to note:
1. The class should be non-copyable? Why? Because most of the time resources classes like file, database, network and locks have no copy semantics.
2. Destructors might encounter throws while releasing resources and the destructors itself should handle this because destructors don't return and can't propagate anything outside.

OK. All Good. So I go ahead and do this.

void setLog(const Foo & foo, const Bar & bar) {
    File* file = new File("/path/to/file", File::append);
    foo.setLogFile(file);
    bar.setLogFile(file);
}
 
This will crash because foo and bar will have invalid  references at the end of the function.
Further, it is important to note that these instances are almost always local variables (they live in the stack or within another object as an attribute); placing them in the heap (thus making them dynamic) makes no sense and could defeat the whole idea behind RAII

What can we do ti alleviate these issues? shared_ptr to the rescue.

void setLog(const Foo & foo, const Bar & bar) { 
    shared_ptr<File> file = new File("/path/to/file", File::append); // reference count 1
    foo.setLogFile(file); // reference count 2
    bar.setLogFile(file); // reference count 3
} // reference count 2
 
Now the shared_ptr will have a reference count of 2 when it exits the function and will not be deleted until the foo and bar objects are destroyed/or until they don't have an references to the *file.

Why is JAVA not into RAII?
Garbage collector.
Having GC means that the destruction of objects is unpredictable. This means that the resources might be tied up and we can't really say when it's going to be released.

By using RAII-modeled classes, the developer need not care about explicitly releasing the acquired resources: they will be freed automatically when the instance that manages them goes out of scope.
 

Comments

Popular posts from this blog

Detaching a process from terminal - exec(), system(), setsid() and nohup

Linux processes are created by fork() and exec(). The very first process of POSIX systems is init and subsequent processes are derived from the init as parent. These subsequent processes are child processes. During forking the parent process copies itself - with all I/O, address space, stack, everything. The only thing that is different is the process ID. The parent and child will have 2 different process IDs. The system() library function uses fork(2) to create a child process that executes the shell command specified in command using execl(3) as follows: execl("/bin/sh", "sh", "-c", command, (char *) 0); system() returns after the command has been completed. system() executes a command specified in command by calling /bin/sh -c command , and returns after the command has been completed. During execution of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT will be ignored.  system() calls are often made within programs to execut

Vaadin vs GWT

From Chapter 1 of book of Vaadin I quote the following. Vaadin Framework is a Java web application development framework that is designed to make creation and maintenance of high quality web-based user interfaces easy. Vaadin supports two different programming models: server-side and client-side . The server-driven programming model is the more powerful one . It lets you forget the web and program user interfaces much like you would program a desktop application with conventional Java toolkits such as AWT, Swing, or SWT. But easier. While traditional web programming is a fun way to spend your time learning new web technologies, you probably want to be productive and concentrate on the application logic. The server-side Vaadin framework takes care of managing the user interface in the browser and the AJAX communications between the browser and the server . With the Vaadin approach, you do not need to learn and deal directly with browser technologies, such as HTML or JavaScript.

C++ Callbacks using function pointers vs boost bind +boost function

In C, the most common uses of callbacks are as parameters to library functions like qsort , and as callbacks for Windows functions, etc. For example you might have a library that provides some sorting functions but you want to allow the library user to provide his own sorting function. Since the arguments and the return values do not change depending on the sorting algorithm, this can be facilitated in a convenient manner using function callbacks. Callbacks are also used as event listeners. onMouseClick(), onTerminalInput(), onData(), onConnectionStatus(), onRead() are probably some examples you've already seen in different libraries. The libraries have these callback functions and the users of the library are supposed to implement them. The library has a function pointer to these functions and calls them on their event loop which will invoke the code of the inherited classes of the library user. The implementation of function pointers is simple: they are just "code p