Skip to content

Test mode: data may occasionally be reset.

RAII

Also known as: Resource Acquisition Is Initialisation

ARM–C++26 current

Tie resource lifetime to object lifetime — whatever an object holds, its destructor releases it automatically.

Manual resource management requires that every resource — memory, file handles, mutex locks, network connections — is released exactly once on every possible exit path from a function. In the presence of early return statements, exceptions thrown by called code, and complex control flow, guaranteeing this manually is tedious and error-prone. Forgetting a single exit path causes a resource leak; releasing on the wrong path causes use-after-free or double-free bugs.

Wrap the resource in a class whose destructor releases it. The C++ language guarantees that the destructor of every local variable is called when the enclosing scope exits — whether by a normal return, a break, or an exception unwinding the stack. The resource is therefore released automatically on every exit path, with no explicit cleanup code required at the call site.

Acquisition typically happens in the constructor, but it need not: std::unique_ptr::reset(), std::fstream::open(), and container push_back() all acquire resources on an already- constructed object. The invariant that defines RAII is on the release side: whatever the object holds at the moment of destruction, the destructor cleans it up.

The Initialisation in the name carries a precise meaning. Initialisation — completing the constructor without throwing — marks the start of the object's lifetime. Once that lifetime has started, the C++ language guarantees the destructor will run. Conversely, if the constructor throws, the object's lifetime never begins and no destructor is called; but that is safe, because a throwing constructor signals that the resource was never successfully acquired.

The consequence is that a constructed object is always valid: it has no "null" or "uninitialised" state that callers must check for. The object is the resource. Ownership, validity, and lifetime are all one thing.

The name Resource Acquisition Is Initialisation was coined by Bjarne Stroustrup in the early 1990s, predating the C++ standard. The acronym RAII is more widely used than the full phrase.

File handle C++11

Guarantees `fclose` is called even if an exception propagates out of the function.

#include <cstdio>
#include <stdexcept>

class File {
public:
    explicit File(const char* path, const char* mode)
        : handle_(std::fopen(path, mode))
    {
        if (!handle_)
            throw std::runtime_error("failed to open file");
    }

    ~File() { std::fclose(handle_); }

    // Ownership is unique; disable copying.
    File(const File&)            = delete;
    File& operator=(const File&) = delete;

    std::FILE* get() const { return handle_; }

private:
    std::FILE* handle_;
};

void process(const char* path) {
    File f(path, "r");
    // use f.get() — ~File() runs on return or exception
}
Scoped mutex lock C++11

The standard library ships RAII wrappers for mutexes: `std::lock_guard` for simple cases and `std::unique_lock` when the lock must be released early or transferred.

#include <mutex>

std::mutex mtx;

void update_shared_state() {
    std::lock_guard<std::mutex> lock(mtx);
    // mtx is held for the duration of this scope
}   // lock is destroyed here → mtx.unlock() called automatically

Advantages

  • Cleanup is automatic and unconditional — it is impossible to forget a release.
  • Exception safety is provided for free: destructors run during stack unwinding.
  • RAII objects compose naturally; a class that owns several RAII members typically needs no destructor of its own (the Rule of Zero).
  • Ownership semantics are explicit in the type: the wrapping class owns the resource.

Disadvantages

  • Destructors cannot propagate exceptions or return error codes. If releasing a resource can fail (e.g. flushing a buffered file), the error must be silently discarded, logged, or communicated through a side channel.
  • Acquiring a resource in the constructor prevents trivially default-constructing an "empty" object; workarounds include nullable state or std::optional.
  • Resources that must be released in a precise order across several objects require careful scope and lifetime design.
Related
  • Container draft
  • Smart Pointer not yet written
Last updated 2026-07-05