RAII and Resource Management¶
RAII—Resource Acquisition Is Initialization—binds a resource's lifetime to an object. Construction establishes ownership and destruction releases it. This applies to memory, files, sockets, locks, transactions, and other resources.
Deterministic cleanup¶
Automatic objects are destroyed when their scope exits, including during stack unwinding after an exception. Member and base destructors then release their resources in reverse construction order.
std::string first_line(std::filesystem::path const& path) {
std::ifstream input{path};
if (!input) throw std::runtime_error{"cannot open input file"};
std::string line;
if (!std::getline(input, line)) {
throw std::runtime_error{"cannot read first line"};
}
return line;
} // input closes here on every exit path
No explicit close() path is required for correctness. Destructors used for
cleanup should not allow exceptions to escape during stack unwinding.
Ownership tools¶
- direct values and standard containers: preferred default;
std::unique_ptr<T>: exclusive dynamic ownership;std::shared_ptr<T>: reference-counted shared ownership;std::weak_ptr<T>: non-owning observation of shared state and cycle breaking;- raw pointers/references: normally non-owning access when their lifetime contract is clear.
Prefer std::make_unique and std::make_shared where their construction and
allocation semantics fit. Shared ownership has atomic reference-count overhead
and does not make the pointed-to object thread-safe.
Locks are resources¶
std::mutex mutex;
std::vector<int> values;
void append(int value) {
std::lock_guard guard{mutex};
values.push_back(value);
}
The guard unlocks during every exit path. std::scoped_lock can acquire multiple
mutexes using a deadlock-avoidance mechanism, though the larger locking protocol
still needs design.
Custom resource handle¶
A resource wrapper should acquire or receive one resource, expose only valid operations, release in its destructor, and define copy/move semantics explicitly. Often it is movable but not copyable.
RAII versus garbage collection¶
Garbage collection reclaims unreachable memory according to a runtime policy. RAII ends resource ownership at deterministic scope/object-lifetime boundaries. C++ can use tracing collectors in specialized environments, and Java can use scope-based resource wrappers; the concepts are not mutually exclusive.
Exercises¶
- Wrap a C file handle in a movable RAII class.
- Explain why a cycle of
shared_ptrowners leaks without a weak edge. - Describe why explicit
lock()followed byunlock()is exception-unsafe.