The Opt-In Problem: Why C++26 Safety Features Leave the Hard Part Unaddressed
Source: lobsters
The C++ committee is aware of the memory safety crisis. Government advisories from NSA and CISA, a decade of research on memory corruption vulnerabilities, and persistent pressure from the security community have made this hard to ignore. C++26 responds with real additions: contracts, hardened standard library containers, and profiles. This piece on Lobsters takes a clear-eyed look at whether those additions actually change the picture.
They probably don’t. The reason is structural.
What C++26 Actually Adds
Contracts give you preconditions, postconditions, and assertions with well-defined evaluation semantics:
int divide(int a, int b)
pre(b != 0);
Hardened containers turn out-of-bounds accesses from undefined behavior into termination. Profiles let you annotate translation units with safety constraints the compiler can enforce at boundaries.
For new code written by disciplined teams, these features are meaningful. They reduce a real class of bugs and make violations visible rather than silently exploitable.
The Structural Issue
The safety argument for C++ requires every piece of code in your call graph to participate. A single unsafe function, an old library dependency, or a vendor SDK you can’t modify can violate the invariants your careful profile annotations establish.
Rust addresses this by inverting the default. Unsafe operations require an explicit unsafe block, making the unsafe surface area explicit and bounded. In a C++ codebase, the unsafe surface area is everything that hasn’t opted into the new features, which in most production systems is the majority of the code.
Profiles help at the margin. A profile-checked module can signal its expectations and warn when callers violate them. But profiles are opt-in at the project level, and compiler vendors have discretion over implementation and enforcement. The result is a patchwork rather than a guarantee.
What This Means in Practice
C++26 safety features raise the ceiling for careful, forward-looking code. They don’t raise the floor. A project that mixes modern C++ with legacy dependencies, which describes nearly every real production system, gets the new features where applied and nothing where they aren’t.
This is a coherent design position. C++ has always prioritized backward compatibility and developer agency over enforced guarantees. That’s not changing in C++26.
The honest framing is that these features give engineers better tools without mandating they use them. Whether industry-wide memory safety incidents decline as a result depends on adoption rates, toolchain enforcement, and organizational code review culture. None of that is specified in a language standard.
C++ is improving. The problem is structural, and structural problems require ecosystem change, not just new syntax.