On one hand, I’m pleased that C++ is answering the call for what I’ll call “safety as default”, since as The Register and everyone else since pointed out, if safety constructs are “bolted on” like an afterthought, then of course it’s not going to have very high adoption. Contrast this to Rust and its “unsafe” keyword that marks all the places where the minimum safety of the language might not hold.
On the other hand, while this Safe C++ proposal adopts a similar notion of an “unsafe” context, it also adds a “safe” keyword, to specify that a function will conform to compile-time safety checks. But as the proposal readily admits:
Rust’s functions are safe by default. C++’s are unsafe by default.
While the proposal will surely continue to evolve before being implemented, I forsee a similar situation as in C where code that lacked initial const-correctness will struggle to work with newer code and libraries. In this case, it would be the “unsafe” keyword that proliferates everywhere just to call older, unsafe code from newer, safe callers.
Rust has the advantage that there isn’t much/any legacy Rust to upkeep, and that means the volume of unsafe code in Rust proframs is minimal, making them safer overall today. But for Safe C++ code, there’s going to be a lot of unsafe legacy C++ code and that reduces the safety benefit for programs overall, for the time being
Even as this proposal progresses, the question of whether to start rewriting some code anew in Rust remains relevant. But this is still exciting as a new option to raise the bar in memory safety in C++.
I was once working on an embedded system which did not have segmented/paged memory and had to debug an issue where memory corruption preceded an uncommanded reboot. The root cause was a for-loop gone amok, intending to loop through a linked list for ever member of an array of somewhat-large structs. The terminating condition was faulty, so this loop would write a garbage byte or two, ever few hundred bytes in memory, right off the end of the 32 bit memory boundary, wrapping around to the start of memory.
But because the loop only overwrote a few bytes and then overflew large swaths of memory, the loop would continue passing through the entire address space over and over. But since the struct size wasn’t power-of-two aligned, eventually the garbage bytes would write over the crucial reset vector, which would finally reboot the system and end the misery.
Because the system wouldn’t be fatally wounded immediately, the memory corruption was observable on the system until it went down, limited only by the CPU’s memory bandwidth. That made it truly bizarre to diagnose, as the corruption wasn’t in any one feature and changed every time.
Fun times lol