1. Problem It Solves
A function that acquires a resource and then throws can skip a cleanup statement at its end. RAII makes cleanup a destructor's responsibility, so the resource is released when its owning object leaves scope during exception handling.
2. Prerequisites
Constructors, destructors, and local variable scope.
throw,try,catch, and how exceptions travel from a called function to a handler.
3. Core Idea
RAII means Resource Acquisition Is Initialization: place resource ownership in an object. std::unique_ptr owns memory, std::lock_guard owns a period of holding a lock, and a file stream manages an open file.
When unwinding toward a handler, fully constructed automatic objects are destroyed in reverse construction order. If a constructor throws, the incomplete object's own destructor does not run; fully constructed members and bases are still destroyed. See destruction during exception handling.
4. Minimal Syntax
auto owner = std::make_unique<Resource>();
operation_that_may_throw();This needs <memory> and definitions of Resource and the operation. When an exception exits this scope toward a handler, owner destroys Resource without a separate delete in each error path.
5. How It Works
Put each successfully acquired resource into an owning object immediately; avoid a gap in which only a raw pointer tracks it.
Perform the work. Normal scope exit or exception unwinding invokes the destructor to release the resource.
Separate cleanup from preserving application state. If you increment a counter and the next step throws, RAII does not automatically decrement it.
Choose the guarantee: the basic guarantee preserves invariants and prevents leaks; the strong guarantee leaves observable state unchanged on failure. A strong guarantee often requires preparing a result separately, then committing through a non-throwing operation.
6. Common Mistakes
Assuming RAII automatically rolls back all data changes.
Keeping a newly allocated resource in a raw pointer across a call that might throw.
Allowing an exception to escape a destructor during exception unwinding; this invokes
std::terminate.Expecting cleanup after
abort,std::terminate, or forced process termination. These are not ordinary scope exits.
7. When to Use It
Use RAII for paired acquisition/release operations: memory, locks, files, and sockets. Prefer existing owning types; when writing your own, define ownership clearly and prevent exceptions from escaping the destructor.
8. Simple Example
The central operation in the C++20 sample is:
void work() {
const auto resource = std::make_unique<Resource>();
throw std::runtime_error{"failure"};
}Resource has a destructor that prints released. main catches the exception and prints caught, so released appears first. Destructor output only illustrates ordering; a real destructor must still uphold its non-throwing contract.
Complete sample code
Source file
dailycppinterview/170_raii-and-exception-safety/main.cpp
// Real-World C++ Interviews Q170: How can RAII (Resource Acquisition Is Initialization) help
// with exception safety?
// Key: RAII stores resource ownership in an object's state: construction establishes ownership
// and the destructor releases it. Because destructors of fully constructed automatic objects
// run during normal return and stack unwinding, files, locks, memory, and other resources are
// released without duplicated cleanup paths. RAII prevents leaks but does not by itself
// guarantee transactional state; strong exception guarantees may also require
// commit-after-success designs such as copy-and-swap.
#include <iostream>
#include <memory>
#include <stdexcept>
struct Resource {
~Resource() { std::cout << "released" << std::endl; }
};
void work() {
const auto resource = std::make_unique<Resource>();
throw std::runtime_error{"failure"};
}
int main() {
try {
work();
} catch (const std::exception&) {
std::cout << "caught" << std::endl;
}
}
9. Key Takeaways
RAII answers who cleans up a resource and when. Keeping application data unchanged after a failed operation requires an appropriate update strategy as well.
10. Self-Check Question
Full question: How can RAII (Resource Acquisition Is Initialization) help with exception safety?
Why does released appear before caught in the sample? If the function changes a counter before throwing, does RAII restore it? What gets destroyed when a constructor fails?