Skip to content

/glossary/cpp/raii

What is RAII in C++? (Resource Acquisition Is Initialization)

verified onenvironmentlocal · linux 6.18.44-fc-v233 x64 · GNU bash 5.2.21updated
tool
C++
versions
C++11, C++17, C++20
os
any

RAII, short for Resource Acquisition Is Initialization, is the C++ idiom of tying a resource to the lifetime of an object: the constructor acquires it and the destructor releases it. The resource is then freed on every way out of the scope, including early return and exceptions, with no cleanup code at each exit.

How it works

C++ guarantees that a local object's destructor runs when the object goes out of scope, in reverse order of construction. RAII uses that rule. A class owns one resource, makes it valid in the constructor (or throws if it cannot) and frees it in the destructor. Code that uses the object cannot forget the release, because it is not written by the user.

The C++ Core Guidelines state the same principle: do not manage a resource by hand, and let an object that owns it manage it.

Standard library RAII types

TypeResource it ownsReleased when
`std::unique_ptr<T>`One heap objectThe pointer is destroyed or reset
`std::shared_ptr<T>`A heap object shared by several ownersThe last owner is destroyed
`std::vector`, `std::string`Their element storageThe container is destroyed
`std::ifstream`, `std::ofstream`An open fileThe stream is destroyed
`std::lock_guard`, `std::scoped_lock`A locked mutexThe guard leaves scope

See the order of events

The program below prints a line when the object is created and destroyed, so you can see the release on a normal exit and on an exception.

bash
mkdir -p /tmp/work && cd /tmp/work
cat > raii.cpp <<'EOF'
#include <iostream>
#include <stdexcept>
struct Guard {
    const char* name;
    explicit Guard(const char* n) : name(n) { std::cout << "acquire " << name << "\n"; }
    ~Guard() { std::cout << "release " << name << "\n"; }
};
void work(bool fail) {
    Guard a("A");
    Guard b("B");
    if (fail) throw std::runtime_error("boom");
    std::cout << "work done\n";
}
int main() {
    work(false);
    try { work(true); } catch (const std::exception& e) { std::cout << "caught " << e.what() << "\n"; }
}
EOF
g++ -std=c++17 -Wall -o raii raii.cpp && ./raii

Output

acquire A
acquire B
work done
release B
release A
acquire A
acquire B
release B
release A
caught boom

Both runs release B before A, and the second run releases them before the catch block starts.

Rules for writing your own RAII class

  1. One class, one resource. If a class owns two resources, an exception in the second acquisition can leak the first.
  2. Acquire in the constructor. If acquisition fails, throw; a constructor that throws leaves no object to clean up.
  3. Release in the destructor, and never throw from it. Destructors are noexcept by default since C++11.
  4. Decide copy and move. A class that owns a unique resource should delete copying and allow moving, as std::unique_ptr does. This is the "rule of five".
  5. Prefer an existing owner. Wrap a C handle in std::unique_ptr with a custom deleter before writing a new class.

Common mistakes

  • Calling new and storing the result in a raw pointer; a throw before delete leaks the object.
  • Using lock() and unlock() by hand instead of std::lock_guard; an early return leaves the mutex locked.
  • Holding a RAII object in a temporary that is destroyed at the end of the full expression, for example std::lock_guard<std::mutex>(m); without a name, which locks and unlocks at once.

FAQ

Does RAII mean I never write delete or close?

In normal application code, yes. Containers, std::unique_ptr, std::shared_ptr, std::fstream and std::lock_guard each own one resource and release it in their destructor. You only write a destructor yourself when you wrap a resource that has no standard owner, such as a handle from a C library.

What happens to RAII objects when an exception is thrown?

During stack unwinding the runtime destroys every fully constructed local object in reverse order of construction, so their destructors run and release their resources. That is why RAII gives exception safety without try/finally. A destructor must not let an exception escape while unwinding, or the program terminates.

Is garbage collection the same as RAII?

No. A garbage collector frees memory at some later, unspecified time. RAII releases the resource at a known point, the end of the scope or the owner's destruction, and it works for any resource, such as files, sockets and mutexes, not only memory.

Sources