Modern C++ gives us strong tools for expressing lifetime, ownership, and constraints. The useful question is not whether a feature is modern, but whether it makes the next engineer’s mental model smaller.
Ownership should be visible
Prefer values by default. Use std::unique_ptr for exclusive dynamic ownership and std::shared_ptr only where ownership is genuinely shared. A raw pointer can remain a useful non-owning view when its lifetime is clear.
class Worker {
public:
explicit Worker(std::unique_ptr<Queue> queue)
: queue_(std::move(queue)) {}
private:
std::unique_ptr<Queue> queue_;
};Make invalid states difficult
Small domain types beat loosely related primitives. Constructors can establish invariants, enums can represent closed choices, and std::optional can say that absence is expected.
Keep control flow boring
Templates, ranges, and metaprogramming earn their place when they reduce duplication without hiding cost or behavior. If debugging requires reconstructing several layers of indirection, the abstraction is charging interest.
Good modern C++ feels explicit: lifetimes are legible, resource release is automatic, and the code communicates where expensive or fallible work happens.