Value vs. reference semantics

Core semantics7 standards

Regular types, when to copy, when identity matters.

Move semantics makes value types cheap enough to pass around, so the default flips toward values: entities (identity, non-copyable) stay behind unique_ptr; everything else aspires to be a regular type.

struct Point { int x, y; };                 // value: copyable, comparable
class Connection {                           // entity: identity matters
  Connection(const Connection&) = delete;
  Connection& operator=(const Connection&) = delete;
};

No change in the model; relaxed constexpr quietly lets more value types live at compile time.

optional, variant and any make composed value types practical (sum and maybe types by value), and guaranteed elision lets factories return non-movable values.

using Shape = std::variant<Circle, Rect, Path>;  // closed set, by value
std::optional<Config> load(std::string_view path);

<=> plus std::regular make regularity cheap and nameable: default the comparisons, constrain templates on std::regular T, done.

struct Version {
  int major{}, minor{}, patch{};
  auto operator<=>(const Version&) = default;   // regular in one line
};
static_assert(std::regular<Version>);

std::expected<T, E> extends the value-semantic style to fallible results — errors travel by value instead of by exception or out-param.

std::indirect / std::polymorphic remove the last big excuse for reference semantics in members: even heap-allocated and polymorphic state can now behave like a value (deep copy, deep const).

struct Node {
  std::string name;
  std::polymorphic<Expr> expr;   // copyable AST node, rule of zero
  bool operator==(const Node&) const = default;
};
C++29direction · not adopted

Direction: pattern matching (P2688) would make consuming sum-typed values (variant, expected) first-class, strengthening the value-oriented style further.

C++26 per the final working draft; C++29 rows are proposals and direction, not adopted features.