C++ Is Getting A Borrow Checker
Based on The PrimeTime's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.
Safe C++ is an opt-in, feature-flagged extension of C++ that aims to enforce memory and thread safety without breaking existing codebases.
Briefing
C++ is moving toward a “safe subset” model—aiming to deliver Rust-like memory safety without abandoning C++’s existing ecosystem. A new proposal for “safe C++” would prohibit undefined behavior inside explicitly marked safe regions, require developers to opt out into unsafe code for operations that can’t be proven safe, and introduce a borrow-checking workflow similar to Rust’s. The practical goal is to let organizations keep writing C++ while reducing the most dangerous classes of bugs: use-after-free, uninitialized reads, and certain data-race hazards.
The proposal’s core mechanism is a feature-flagged extension of C++ that remains backward compatible: existing code should still compile normally, and safety checks only activate when developers choose the new model. Under the hood, the compiler lowers safe functions into an intermediate representation and then performs borrow checking on that form. A new `safe` modifier marks safe scopes, while an `unsafe` keyword gates pointer operations and other operations that can violate the safety guarantees. In effect, old C++ code is treated as unsafe by default, so developers would wrap unsafe operations inside clearly delimited blocks rather than mixing them invisibly throughout a program.
Safety is defined in categories. Lifetime safety targets uninitialized-variable bugs and use-after-free. Borrow checking is used to prevent invalid aliasing and to support a “destructive move”/relocation concept—once a value is moved, it can’t be used again. Type safety focuses on null-related hazards and other invalid states, with the proposal calling for safer alternatives such as choice/tagged union types when unions and raw pointers would otherwise be used. Runtime safety adds checks like bounds checking (for example, preventing out-of-range indexing) and other inserted protections, with the option to skip some checks in performance-critical paths.
Thread safety is also part of the plan, borrowing the Rust framing: types would be marked as safe to send across threads (`Send`) and safe to share between threads (`Sync`). The proposal suggests using concepts/constraints and interface-like queries to express these properties, so the compiler can reject unsafe cross-thread usage at compile time.
A major adoption question hangs over the proposal: rewriting existing C++ codebases is expensive, and Rust’s semantics differ enough from C++ that a full migration would require substantial developer retraining and code restructuring. The safe C++ approach tries to avoid that by extending C++ rather than replacing it. Still, the transcript repeatedly flags friction points—especially around interoperability with existing C and C++ libraries, the overhead of safety checks, and the complexity of the eventual syntax for safe references/borrows.
Even with those uncertainties, the direction is clear: safe C++ aims to make “accidental memory corruption” harder by construction, while preserving the ability to drop into unsafe code when necessary. The result would be a hybrid language model—C++ where safety is opt-in and enforced by compiler analysis, not just developer discipline.
Cornell Notes
Safe C++ is a proposal to add an opt-in, Rust-like safety model to C++ without breaking existing code. It would introduce a `safe` scope and require developers to use `unsafe` blocks for operations that can’t be proven safe, with old C++ treated as unsafe by default. The compiler would perform borrow checking on lowered intermediate representations, and safety guarantees would be grouped into lifetime safety, type safety, runtime safety, and thread safety (via Rust-style `Send`/`Sync` concepts). The motivation is to reduce undefined behavior and memory bugs while avoiding a full rewrite into Rust, since Rust and C++ semantics differ and migration is costly. The biggest open issues are syntax complexity, interoperability with existing libraries, and performance/overhead tradeoffs.
What does “safe C++” try to change about how C++ code is written and compiled?
How does the proposal handle memory lifetime and move semantics?
What replaces risky C++ features inside the safe subset?
How does safe C++ address concurrency and data races?
Why not just rewrite everything in Rust instead of extending C++?
What are the practical concerns raised about adopting this approach?
Review Questions
- What compiler analysis steps are described for enforcing safety in safe C++ (and where does borrow checking fit)?
- How do `safe` and `unsafe` interact in the proposal, and what kinds of operations are expected to be restricted in safe code?
- Which four categories of safety are named, and what is the role of `Send`/`Sync` within thread safety?
Key Points
- 1
Safe C++ is an opt-in, feature-flagged extension of C++ that aims to enforce memory and thread safety without breaking existing codebases.
- 2
A `safe` modifier marks safe scopes, while an `unsafe` keyword explicitly contains operations that can violate safety rules; old C++ is treated as unsafe by default.
- 3
The compiler would lower safe code to an intermediate representation and run borrow checking similar to Rust to prevent invalid aliasing and lifetime errors.
- 4
Safety guarantees are organized into lifetime safety, type safety, runtime safety, and thread safety, with runtime checks like bounds checking and optional skipping for performance.
- 5
Thread safety would use Rust-style `Send`/`Sync` properties expressed via constraints/concepts to reject unsafe cross-thread usage at compile time.
- 6
The proposal includes safer alternatives to risky features (e.g., choice/tagged union types) when unions and raw pointer patterns would be disallowed in safe regions.
- 7
Adoption hinges on interoperability with existing C/C++ libraries, the eventual ergonomics of the safe syntax, and the performance cost of inserted checks.