RAII is Resource Acquisition Is Initialization, and it’s a neat concept once you understand what it means and how it’s used. RAII was born out of C++ and invented by its creator Bjarne Stroustrup.

In C++, the only code that can be guaranteed to be executed after an exception is thrown are the destructors of objects residing on the stack. Resource management needs to be tied to the lifespan of suitable objects in order to gain automatic allocation and reclamation. Resources are acquired during initialization, and guaranteed to be released with the destruction of the same objects.

For local objects allocated on the stack, the languages scoping rules ensure that the destructor is called when its scope ends. Thus, by putting the resource release logic in the destructor, C++’s scoping provides direct support for RAII¹:

#include <iostream>
#include <chrono>

using namespace std::chrono;

class Timer {
    system_clock::time_point start, finish;
    public:
    Timer() {
        start = system_clock::now();
    }
    ~Timer() {
        finish = system_clock::now();
        nanoseconds ns = finish - start;
        std::cout << "Total time: "
            << ns.count() << " nanoseconds" << std::endl;
    }
};

int main() {
    Timer t;
    // some long expensive calculation
}

In this snippet, the Timer class demonstrates using RAII to calculate and display the time it takes for a portion of code to execute. A Timer object, t, is initialized in the first line of the main function, which will be used to calculate and display the global time the program took to execute. Once some long, expensive calculation runs, the main program will exit and the Timer object will display the duration it took for the program to execute. Very handy for performance debugging.

Smart Pointers

Consequently, this is how the C++11 library shared_ptr works. It is a reference counting smart pointer that shares ownership, so when the last copy of it goes out of scope it will free the managed object. In case you’re wondering, unique_ptr and shared_ptr live in the header <memory>.

A smart pointer is a class that imitates raw pointers by overloading operators. unique_ptr is powered by rvalue references, a C++11 feature. While it is not copyable, it is movable. With unique_ptr and shared_ptr, std::move can be used as a helper function that moves its resources into a different object. The main difference between unique_ptr and shared_ptr is that unique_ptr does not have shared-ownership, meaning there is only one reference available at a time²:

int main() {
    std::unique_ptr<int> p(new int(42));
    std::unique_ptr<int> p2 = std::move(p);
    assert(p == nullptr);
    std::cout << *p2;
}

One useful example of this is the pimpl idiom, where you have a pointer to some class that implements all of its methods. This is useful for breaking out dependencies allowing your program to compile faster.

There is a smarter pointer available called shared_ptr, originally developed for the Boost library but now part of the C++11 standard. shared_ptr objects have shared ownership, meaining the last remaining owner of the pointer is responsible for destroying the object, or otherwise releasing the resources associated with the stored pointer³.

int main() {
  std::shared_ptr<int> sp(new int(42));
  std::shard_ptr<int> sp2(sp);
  std::cout << *sp << " " << *sp2;
}

References