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_ptrfor exclusive ownership. - Use references or raw pointers for non-owning views.
- Use
shared_ptrrarely, and only for true shared ownership.