Summary
Practical notes on expressing ownership and object lifetimes in modern C++ with smart pointers and references.

Modern C++ gives you precise tools for saying who owns an object and how long it lives. Using them well makes bugs visible in the signature.

Value by default

Unless you need indirection, store objects by value. It is simpler and usually faster.

struct Point { double x, y; };
struct Shape {
std::string name;
std::vector<Point> vertices;
};

Shape owns its name and vertices. Copying a Shape copies everything, and its lifetime is tied to the variable — no leaks, no manual cleanup.

Unique ownership

When an object must outlive its creating scope, use std::unique_ptr:

#include <memory>
class AudioStream {
public:
explicit AudioStream(std::string source);
// ...
};
auto stream = std::make_unique<AudioStream>("intro.wav");

unique_ptr expresses single ownership. When the unique_ptr is destroyed, the stream is destroyed too. It cannot be copied, so a copy-and-forget bug becomes a compile error.

Shared ownership

Only reach for shared_ptr when multiple owners genuinely exist, and measure before assuming it is needed:

std::shared_ptr<Cache> cache = std::make_shared<Cache>(64);

Prefer passing raw T* or T& for non-owning access. The absence of an ownership wrapper tells the reader I do not own this.

The rule of thumb

  • Default to value types.
  • Prefer unique_ptr for exclusive ownership.
  • Use references or raw pointers for non-owning views.
  • Use shared_ptr rarely, and only for true shared ownership.