RAII: let objects clean up
Memory from new, an open file, a lock: each must be given back exactly once, and hand-written cleanup is easy to skip. RAII ties a resource to an object: the constructor takes it and the destructor gives it back, and C++ runs the destructor on every way out of a scope. Follow a small class Buf as it takes four ints from the heap and returns them on an early return and during an exception.
5 quick questions
Pick an answer to see why. Your score saves with your progress.
01In void manual(bool stop) { int* p = new int[4]{}; if (stop) return; delete[] p; }, what happens when stop is true?
The early return jumps past the hand-written delete[]. Nothing points at the memory any more, so it stays taken: a leak.
02What does RAII stand for, and what is the idea?
RAII ties a resource's life to an object's life: acquire it while initializing the object, release it in the destructor.
03When does C++ call the destructor of a local object such as Buf b?
A local object's life ends with its scope, however the scope is left, and C++ then calls its destructor automatically, exactly once.
04An exception is thrown inside work after Buf b; and is caught in main. What happens to b's memory?
As an exception travels to its catch, C++ unwinds the stack and runs the destructors of the objects in each scope it leaves.
05Which of these does NOT manage a resource with RAII?
A raw pointer has no destructor that frees what it points at; you must call delete[] yourself. The other three give their resource back in their destructors.
Glossary
- Resource
- Something a program borrows and must give back exactly once, such as heap memory, an open file or a lock.
- RAII
- Resource Acquisition Is Initialization: an object takes a resource when it is made and releases it in its destructor.
- Destructor
- A special member function, written ~ClassName(), that C++ calls automatically when an object's life ends.
- Scope
- The part of the code, usually between { and }, where a local object exists. When the scope ends, its objects are destroyed.
- Heap
- The memory you take with new and give back with delete; its objects live until you delete them (dynamic storage).
- Memory leak
- Memory that was taken and never given back, usually because nothing points at it any more.
- Stack unwinding
- What C++ does as an exception travels to its catch: it leaves each scope and runs the destructors of the objects in it.
- std::unique_ptr
- A standard smart pointer that owns one heap object or array and deletes it in its destructor. It can be moved but not copied.
Notes and sources
- The card is real C++. Add int main() { work(true); work(false); } and it compiles with g++ -std=c++20 -Wall -Wextra with no warnings. A counting operator new[]/delete[] confirms every block comes back.
- 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.
- When b is destroyed, the destructor's body runs first (delete[] p), then b's members are destroyed, then its storage on the stack ends when work returns.
- 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.
- Buf as written is not safe to copy: a copy would hold the same pointer, and both destructors would delete it (the rule of three). Copying and moving are how a class fixes that; std::unique_ptr forbids copying and allows moving.
- 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.
- cppreference.com: RAII
- cppreference.com: Destructors
- cppreference.com: Throwing exceptions (stack unwinding)
- cppreference.com: new expression
- cppreference.com: Non-static data members (default member initializers)
- cppreference.com: The rule of three/five/zero
- cppreference.com: std::unique_ptr
- cppreference.com: std::lock_guard
- C++ Core Guidelines (isocpp.github.io): R.1 Manage resources automatically using RAII
- Standard C++ Foundation (isocpp.org): Exceptions and Error Handling FAQ
Quiz Unlocks after the last step.