Pointers, Lifetimes, and Ownership¶
Memory safety in C++ depends on more than whether a pointer is null. A pointer or reference must designate an object whose lifetime has begun, has not ended, and permits the requested operation.
Storage and object lifetime¶
Storage provides bytes with alignment. An object's lifetime begins and ends according to construction, destruction, and language rules. Storage can outlive an object, and a pointer value can remain non-null after the designated object's lifetime ends.
Dereferencing the result has undefined behavior. The defect is lifetime, not the bit pattern held by the pointer.
Prefer values and scoped owners¶
std::vector<widget> values; // owns widget values
auto owner = std::make_unique<widget>(); // exclusive dynamic owner
widget& alias = *owner; // non-owning; owner must outlive use
Dynamic allocation is not required merely because an object is large. Use it when runtime lifetime, polymorphism, stable address, graph structure, or another explicit requirement makes indirection appropriate.
Pointer arithmetic¶
Pointer arithmetic is defined only within an array object (plus its one-past
position) under the language rules. A one-past pointer may be compared or used
as an end sentinel but not dereferenced. Prefer iterators, ranges, and std::span
to pointer-plus-length pairs.
Ownership contracts¶
| Interface | Meaning |
|---|---|
T |
Independent value |
T& / T const& |
Required non-owning alias |
T* / T const* |
Often optional/reseatable non-owning alias |
std::unique_ptr<T> |
Exclusive ownership transfer |
std::shared_ptr<T> |
Shared ownership |
std::weak_ptr<T> |
Non-owning observation of shared ownership |
std::span<T> |
Non-owning contiguous range |
Types do not encode every lifetime fact. A reference can still dangle, and returning a span to local storage is invalid.
Invalidation¶
Container operations can invalidate iterators, pointers, references, and views. For example, vector reallocation invalidates all references into its elements. Read the specific operation's contract; there is no universal “container references remain valid” rule.
Manual allocation¶
Direct new/delete and new[]/delete[] pairs are error-prone under early
return, exceptions, ownership transfer, and partial construction. Encapsulate
low-level allocation inside standard containers, smart pointers, allocators, or
audited resource types.
Exercises¶
- Identify every lifetime dependency in a class storing
std::string_view. - Explain why a non-null pointer may still be invalid.
- Refactor a
new[]/delete[]buffer tostd::vector.