|
|
|
|
|
by damon_dam
494 days ago
|
|
Agreed. I would add to your argument as follows. If you stick with "21st Century C++" [1], you never have to use a pointer. At some point, there will be (say) a -W20 flag that produces a warning if you use a pointer or other potentially-unsafe idiom without marking it with a [[20th_century]] attribute. That attribute is equivalent to Rust's unsafe keyword. At that point, the safety difference will boil down to opt-in versus opt-out. But you can already opt-in today by policing yourself. That's quite far from the radical language difference it's made out to be. [1] https://news.ycombinator.com/item?id=42946321 |
|
There's many examples, but one I stumble on often is functions that accept a std::string_view, and return a part of that string. It's quite dangerous to make it return a std::string_view as well, especially given how easy it is to create temporaries (e.g. get_word(sentence1 + sentence2) would return a string_view to temporary data). Similar story with functions that return element references out of collections, functions that choose an element out of two, etc.
In Rust on the other hand, you can get very reckless with very long chains of functions that return references out of other references, especially with parsers, iterators, and lambdas/closures.
The Send/Sync traits for thread safety are also unmatched in C++, tagged union pattern matching will also heavily restrict invalid states, and so will Rust's affine(ish) types, which force a single owner for resources, as opposed to C++'s somewhat hard-to-use move semantics.
The standard library also prefers safety over speed by default, e.g. with std::string_view's indexing being UB, std::optional's dereference being UB, and so on.