---
title: RAII
source: 'https://academia.sh/en/courses/cpp-fundamentals/raii'
course: 'C++ Fundamentals and Object Design'
language: en
updated: '2026-09-26T03:02:45+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Defines that RAII acquires a resource in the constructor and releases it in the destructor'
    - 'Measures that the object a guard touches is not itself but the member inside it'
    - 'Shows that the destructor runs even on early exit paths'
---

# RAII

Measures that the member a guard acquires and releases is a part inside the guard object, not the guard itself.

The previous lesson measured when an object is constructed and destroyed, whether it has a name or not. This lesson puts that knowledge to a purpose: releasing a resource safely — here a simple counter-like resource, in real programs it could be memory, a file handle, or a lock. The measurement kind this time is **part**: the thing a guard acquires and releases is not the guard itself, but a data member inside it.

## What RAII Is

**RAII** (Resource Acquisition Is Initialization) is a design pattern that has a resource acquired in an object's constructor and released in its destructor. As long as the object holding the resource is alive, the resource stays valid; when the object — named or temporary, as seen in the previous lesson — reaches the end of its lifetime by any path, the destructor runs and releases the resource. This makes releasing the resource by hand (calling a function like `release()` one by one in every piece of calling code) unnecessary: no matter which path the object holding the resource is destroyed by (reaching the end of a function, an early `return`, throwing an exception), the destructor **always** runs.

RAII's opposite is leaving the resource to the caller's discipline instead of a constructor/destructor pair: an `open_resource()` function is called, used, and a `close_resource()` is expected to be called by hand at every exit point of the code. This approach's fragility shows up as the code grows — when a new early `return` is added to a function, a `close_resource()` call must also be added before that `return`; if it is not added, the resource leaks (leak — the resource stays valid for the rest of the program's run without ever being released). RAII removes this risk by handing the release decision not to the code holding the resource but to the responsibility of **the type of the object holding** it: code that uses `Guard` never writes a release call, because that call is already written once, in the class itself, inside `Resource::~Resource()`. This lesson's first section defines two classes: `Resource`, which actually holds the resource, and `Guard`, which wraps it as a member.

```cpp
// resource.hpp — a simple resource represented by numbers
#ifndef RESOURCE_HPP
#define RESOURCE_HPP

#include <cstdio>

class Resource {
public:
    explicit Resource(int id) : id_(id) {
        std::printf("resource acquired id=%d\n", id_);
    }

    ~Resource() {
        std::printf("resource released id=%d\n", id_);
    }

    int id() const { return id_; }

private:
    int id_;
};

#endif
```

```cpp
// guard.hpp — a guard that acquires and releases the member holding the resource
#ifndef GUARD_HPP
#define GUARD_HPP

#include "resource.hpp"

class Guard {
public:
    explicit Guard(int id) : resource_(id) {}

    int id() const { return resource_.id(); }

private:
    Resource resource_;
};

#endif
```

## What the Guard Releases Is a Part, Not the Guard Itself

`Guard` has its own constructor and a compiler-generated destructor; when `Guard` constructs its `resource_` member, `Resource`'s constructor runs, and when `Guard` itself is destroyed, `resource_` is destroyed and `Resource`'s destructor runs. The question here: is the thing the guard acquires and releases the `Guard` object itself, or the `resource_` member inside it?

```cpp
// part-measurement.cpp — is the resource the guard holds the guard itself or a part inside it
#include <cstdio>

#include "guard.hpp"

int main() {
    std::printf("block started\n");
    {
        Guard g(7);
        std::printf("id %d\n", g.id());
    }
    std::printf("block ended\n");
    return 0;
}
```

```text
block started
resource acquired id=7
id 7
resource released id=7
block ended
```

**CR8.** `Resource`'s constructor is triggered on the `Guard g(7)` line, before `Guard`'s own constructor body runs, by `resource_(id)` in the member initializer list — this is why the `resource acquired` line is seen right after `block started`, before `Guard`'s own body prints anything. The object that actually acquires the resource is `Resource`, and this object is **not** `Guard` itself but a member of it — `resource_` is a subobject inside `Guard`'s memory range, not a separate, independent object. The proof of this is in the ordering: when `g` is destroyed at the end of the block, `Guard`'s (compiler-generated, printing nothing) destructor runs first, and then, because it is a member of `Guard`, `resource_`'s destructor runs — this is why the `resource released` line is seen before `block ended`. If `resource_` were an independent object separate from `Guard`, its destruction would not depend on `Guard`'s destruction; but here the two are triggered at the same moment, by the closing of the same scope — because one is a part of the other.

There is no name collision to worry about here: `Resource` and `Guard` are each their own class, one holding the other as a member. `Guard`'s own constructor, `explicit Guard(int id) : resource_(id) {}`, has no body — the member initializer list does all the work, constructing `resource_` with `id`. `Guard` has no destructor written of its own; the compiler generates one, and this generated destructor, printing nothing itself, merely triggers `resource_`'s destructor — this is the same behavior seen in the previous lesson's `Pair` example: even when a class writes no destructor of its own, its members' destructors still run.

## The Destructor Still Runs on Early Exit Paths

RAII's real value is writing the code that releases the resource in a single place (the destructor) and leaving it to the compiler to run that code on **every** exit path — a function's normal end, an early `return`, or even when an exception is thrown.

```cpp
// early-exit.cpp — does the guard still release on an early return path
#include <cstdio>

#include "guard.hpp"

static void run(bool early_exit) {
    Guard g(9);
    std::printf("run started id=%d\n", g.id());
    if (early_exit) {
        std::printf("exiting early\n");
        return;
    }
    std::printf("finishing normally\n");
}

int main() {
    run(true);
    std::printf("main continues\n");
    return 0;
}
```

```text
resource acquired id=9
run started id=9
exiting early
resource released id=9
main continues
```

**CR9.** When `run(true)` reaches the `return` inside the `if` block, `g`'s scope (the function body) ends, and the compiler runs `g`'s destructor **right before the `return`** — this is why the `resource released` line is seen after `exiting early`, but before `main continues`. This behavior is the same regardless of the `if` branch: had `run(false)` been called, the same destructor would still run right after the `finishing normally` line. The code that releases the resource is written only once, inside `Resource::~Resource()`; `run` itself makes no release call at all.

This guarantee holds not only for regular control flow like `if`/`return`, but also for C++'s exception mechanism: if an exception is thrown (`throw`) inside a function body, the stack **unwinds** (stack unwinding) until that exception is caught by a `catch` block — during this unwinding, the destructors of the local objects in each scope being unwound run in order, exactly as with a normal `return`. Had there been a `throw` line after `g` inside `run`, `g`'s destructor would still run before the exception left `run`. This course does not teach throwing and catching exceptions — that is another topic — but RAII's real strength comes from exactly this: the code that releases the resource does not need to know **which** path control flow exits by, because the destructor runs on every path.

## The Risk of Holding a Resource by Reference

RAII's soundness rests on the guard holding the resource **by value** (as a member, bound to its own lifetime). If a guard holds the resource by reference or pointer, the guard's own lifetime and the resource's real owner's lifetime can diverge — the resource may already be gone while the guard is still alive. `Guard` does not carry this risk because `resource_` is not a reference or a pointer but a direct `Resource` value; as long as `Guard` is alive, `resource_` is alive too, because it is a part of the same object. Had a guard been wrongly designed to hold the resource by pointer instead of by value — something like `Resource* resource_;` — copying the guard would copy only the pointer, not the actual `Resource` object; two guards would point at the same resource, and once one released the resource in its destructor, the other would end up pointing at an invalid resource. This lesson does not run this mistake — it is only mentioned in prose — because releasing a resource twice is undefined behavior.

Solving this sharing problem with the standard library's ready-made RAII wrappers is K05's subject; this course manages the resource with classes it writes itself. M10/K02's (Rust) ownership system and M11/K02's resource management are that same idea's — that a resource has exactly one owner, and the resource is released automatically once the owner's lifetime ends — counterparts in different languages; this lesson does not deepen that comparison.

It is useful to see in more detail how `Guard`'s own design avoids this risk. `resource_` **is** a `Resource` value, not a `Resource*` or a `Resource&`; this is why `resource_` itself (not merely an address pointing at it) sits in the `Guard` object's memory layout. When a `Guard` is copied — this course's next lesson's subject — `resource_` is copied too, because it too is a part of `Guard`; two `Guard`s carry two separate `Resource`s, not sharing the same resource. This is not true for a resource held by pointer: copying the pointer copies only the address, not the pointed-to object, so two guards begin pointing at the same resource. This consequence of holding by value — that copying also copies the resource along with it — is a part of RAII's reliability and is measured in detail in the next lesson.

Holding a resource by value has a limit too: because the resource sits in the holding object's memory layout, the resource's size (or at least the size of the handle representing it) must be known at compile time. This problem does not show up here because `Resource` carries only an `int`; a real resource — an open file, a network connection — is usually represented by a fixed-size handle given by the operating system (for example an integer or a pointer), which is why the same hold-by-value strategy works for real resources too.

## A Guard Holding More Than One Resource

A guard holding more than one resource instead of a single one follows the same rule: each resource becomes another member of the guard, and each member's construction/destruction order follows the declaration-order rule measured in the previous lesson. Had a `DoubleGuard` with two `Resource` members been designed, the members would be constructed in declaration order and destroyed in reverse order — exactly like `first_`/`second_` in the `Pair` example. This lesson does not run `DoubleGuard`, because acquiring and releasing a single resource is enough to show RAII's core idea; but it is important to see that this generalization comes directly from the previous lesson — RAII adds no new language rule, it merely puts the constructor/destructor order to a purpose.

## The Bounding Measurement

The expression this lesson measures is of the **part** kind: `resource_` is not `Guard` itself but a subobject inside it, and it has the same lifetime as `Guard`. But RAII's guarantee depends on the guard **holding the resource by value** — if a guard holds only a reference to the resource (the resource's real owner being some other object), the guard must **not outlive** the protected object; if the protected object is destroyed while the guard is still alive, the guard's reference becomes dangling, and the guard's destructor (if it has one) may try to access an invalid object. This lesson does not run this risk, because running it would trigger undefined behavior; `Guard` here always holds the resource by value, so this risk does not exist to begin with.

A practical consequence of this bound is that when designing a guard, the question "who really owns this resource" must always be answered explicitly. In `Guard` the answer is clear: `Guard` itself owns it, because `resource_` is a value member of it. Had a guard instead wanted to say "I am only observing a resource living elsewhere" — for example wanting to store a `Resource&` taken as a function parameter — this would no longer be RAII, only holding a reference, and the responsibility of releasing the resource would not belong to the guard. Both designs are valid in C++, but they must not be confused with each other: a class's destructor must release only the resources **it itself owns**, not one it has merely borrowed.

The three examples measured throughout this lesson — the proof of construction order, the destructor running on early exit, holding the resource by value — together show why RAII is more than a "best practice": it is a direct consequence of the language's constructor/destructor and declaration-order rules, not a separate mechanism. The next lesson's copying question is also built on this same foundation — when a `Guard` is copied, `resource_` will be copied too, but whether this copy is "deep" or "shallow" can produce different results depending on the resource's type.

## Summary

- The expression this lesson measures is of the **part** kind: `resource_` is not the `Guard` object itself, but a subobject inside it.
- RAII acquires a resource in the constructor and releases it in the destructor; no code that releases the resource by hand is needed.
- The destructor runs regardless of how the scope ends — a normal end, an early `return`, or throwing an exception, it is the same in all of them.
- A guard that holds the resource **by value** binds the guard's lifetime to the resource's lifetime; a guard that holds it by reference loses this guarantee.
- Smart pointers extend RAII to shared resources; this is outside this course's scope (K05).

## Next Step

This lesson measured how a resource is safely held by a constructor/destructor pair; the next lesson asks what this guarantee becomes when an object is **copied** — it measures whether the copy constructor acquires its own resource, or shares the original's.
