RAII becomes systematic: unique_ptr is the default owner, shared_ptr/weak_ptr for shared graphs, rule of five for resource types — and rule of zero for everything else.
classSession {
std::unique_ptr<Socket> sock_; // owns
Logger* log_ = nullptr; // observes, never deletespublic:
explicitSession(std::unique_ptr<Socket> s) : sock_(std::move(s)) {}
// rule of zero: no dtor/copy/move written by hand
};
The observer convention hardens: a raw pointer or reference means non-owning, period. shared_ptr<T[]> works, and weak_from_this arrives via enable_shared_from_this.
// API contract reads from the signature alone:Widget* find(Id id); // may be null, not yoursWidget& at(Id id); // never null, not yoursstd::unique_ptr<Widget> take(Id id); // yours now
std::span and std::string_view give non-owning views a vocabulary, which sharpens ownership audits: anything that is not an owner should usually be a view or a plain pointer/reference.
voidparse(std::span<const std::byte> frame); // borrowed buffer// lifetime rule: the span must not outlive the frame it views
std::indirect<T> and std::polymorphic<T> are value-semantic owners of heap objects: deep-copying, const-propagating, rule-of-zero friendly — the blessed pimpl/polymorphic-member building blocks.
classDoc {
std::indirect<Impl> impl_; // pimpl with real value semantics
std::polymorphic<Shape> shape_; // copies copy the dynamic type
};
Direction only: lifetime-safety profiles and borrow-checking proposals (the “Safe C++” debate) target statically rejecting dangling views; nothing is adopted yet.
C++26 per the final working draft; C++29 rows are proposals and direction, not adopted features.