Object lifetime, references and RAII in C++
When constructors and destructors run, how references differ from pointers, and why RAII makes resource handling safe.
Much of C++ comes down to one question: when does an object start and stop existing? Understanding lifetime explains constructor order, destructor order and the RAII style that modern C++ relies on.
Constructor and destructor order
A local object is constructed when its declaration runs and destroyed when it goes out of scope. Several local objects are destroyed in reverse order of creation. With inheritance, the base part is constructed first and destroyed last.
struct Base { Base() { cout << "B "; } ~Base() { cout << "~B "; } };
struct Derived : Base { Derived() { cout << "D "; } ~Derived() { cout << "~D "; } };
int main() { Derived d; } // B D ~D ~B
References versus pointers
- A reference is another name for an existing object. It must be initialised and cannot be reseated later.
- A pointer holds an address, can be null and can be pointed somewhere else.
- Assigning to a reference changes the original object, not the reference.
int a = 1, b = 2;
int& r = a;
r = b; // a is now 2; r still refers to a
int* p = &a;
p = &b; // p now points to b
Pass large objects as const T& to avoid copying them while promising not to change them.
RAII
RAII stands for resource acquisition is initialisation. A resource such as memory, a file or a lock is acquired in a constructor and released in the destructor. Because destructors run automatically when objects leave scope, even when an exception is thrown, the resource is always released.
{
std::vector<int> v(1000); // memory owned by v
auto w = std::make_unique<Widget>(); // deleted automatically
std::lock_guard<std::mutex> g(m); // mutex released automatically
} // all three are released here
This is why modern C++ rarely calls new and delete directly. If you do use new[], release it with delete[], never with plain delete.
Habit to build
For every resource your code acquires, name the object whose destructor will release it. If there is no such object, wrap the resource in one, or use a standard container or smart pointer.
More in Programming