1struct Buf {2 int* p = new int[4]{};3 ~Buf() { delete[] p; }4};5void work(bool stop) {6 Buf b;7 b.p[0] = 42;8 if (stop) return;9 b.p[1] = 7;10}p[0]–p[1]–p[2]–p[3]–work() frameb.p–new42}del!!leak
Violet card: the code (struct Buf and work)Sand: work's stack frame and the object b; slate: the heap, four intsTokens: new takes memory, del gives it back, a red ! is an exception or a leakLeft: the code raii.cpp. Right, in front: work's stack frame with the object b; behind it: the heap with four ints. Making b runs its constructor, which takes four ints from the heap (new). When b's scope ends, by the closing brace, an early return or an exception, C++ calls ~Buf, which gives them back (delete[]). The manual version, with new and delete written by hand, leaks on the early return. The stack and the heap are the usual way implementations place automatic and dynamic objects; the C++ standard speaks of automatic and dynamic storage duration instead.

The problem

  1. A resource is anything a program borrows and must give back: heap memory from new, an open file, a lock. Each must be returned exactly once. Forget, and it leaks. Return it twice, and the program can crash.

RAII at work

Everywhere

What happens

;; step 1/9 · resource
resource        how you get it        how you give it back
heap memory     new / new[]           delete / delete[]
a file          std::fopen            std::fclose
a lock          m.lock()              m.unlock()
forget to give back  → a leak: it stays taken until the program ends
give back twice      → a double free: behaviour not defined, often a crash

Line 2 is a default member initializer: Buf has no constructor written out, so the compiler makes a default constructor that runs it. Writing Buf() : p(new int[4]{}) {} does the same. Stack unwinding runs destructors when an exception leaves a scope and a matching catch exists. If no catch is found, std::terminate is called and it is up to the implementation whether the stack is unwound first.