upvote
The reality though it many people are not using smart pointers. I have seen many people argue they don't like them because they want to see every place delete is called. (meanwhile of course they never notice all the places it should be called but isn't - but at least where it is they see it)
reply
Personally I love to use smart pointers where bleeding edge performance is not necessary.

If I need the absolute fastest code, then that code will be tortured under valgrind. That’s non-negotiable in my book.

Code is not done until its memory management is proven correct.

reply
It's more than that. Smart pointer help, but there are cases where even when using smart pointers you can encounter memory safety issues. Especially when you need to interact with c or older c++ code that doesn't use smart pointers. And smart pointers don't provide any protection against data races in multi-threaded code, like rust does.
reply
smart pointers solve a different problem than data races
reply
That's my point. C++ doesn't have an equivalent of rust's protections around Send and Sync.
reply
And yet applications written in modern C++ are constantly discovering new memory safety issues. Sean Baxter wrote a whole manifesto talking about the shortcomings of the existing C++ model [0].

[0] https://safecpp.org/draft.html

reply
The problem with manefestos is they often harp on small parts that don't matter much in the big picture. There are real shortcoming of the C++ model, but if you use modern C++ they are rare.

The real shortcoming it is very common for people to not write modern C++. I know several C++ developers who refuse to use smart pointers because they don't like magic happening.

reply
It's not enough for memory safety issues to be "rare". To meet your obligations under the standard and have defined behavior (i.e. rust's basic guarantee), memory safety issues can't exist at all.
reply
Ah, so this article invalidates all of the safety guarantees of rust? Since one hole was found the entire boat is shot and should be left at the bottom of the harbor?

C++ has a terrible reputation which is well associated with, say C++98, if you have a good linter you can bop people on the head for using news anywhere outside a few limited locations where you consider it warranted. All working environments have language features or even programming paradigms that are considered detrimental to code ecosystem health and fighting against these is an organizational lift when working in any programming language. Full type security doesn't mean someone can't create an overly generic object and just start breaking code contracts across the code base. C++ has an awful lot of footguns and more warts than most but it can be made to be sane for development and the new language features really bring it on par with other modern languages.

I have worked in C++ (primarily within the Qt framework which pushed hard into const refs instead of pointers) and it's fine. I've also worked in PHP which can also be fine. Rust isn't something I've worked at scale in but it certainly is very attractive if I ever jump to an org working in it - but even in Rust you'll want to restrict style divergence and bad patterns with linting.

reply
I'm only talking about modern C++, not C++98. C++'s footguns include smart pointers. For example, is the following code safe?

    std::unique_ptr<int> p(foo());
    std::print("{}\n", *p);
The answer depends on how foo() is implemented. You can't reason about it locally, and strictly speaking it's not possible to determine at compile time. Now, I should be declaring this gsl::not_null<std::unique_ptr<int>> to comply with the core guidelines, but I think we can agree that optional support libraries aren't relevant to this discussion.
reply
Throw your computer away then. Rice's theorem and Godel's incompleteness theorem both make anything other than rare impossible.

These issues will exist for all time. The only question is how rare can we make them.

reply
That's trivially untrue. Nothing about turing machines or lambda calculus requires temporal unsafety. Even this example wouldn't exist if the compiler rejected covariant lifetimes. You already know this of course, so I'm not going to keep beating that dead horse.

The obvious follow-up is to find a minimal set of rules that allow us to express what we want without permitting temporal unsafety. The borrow checker is one set of fairly minimal rules that works pretty damn well. Alternatively you could define away the unsafety by giving it semantics, like fil-C does.

reply
C++ still doesn't have a sane modern pattern for tagged unions. If you want to define a type to represent, say, a simple parse tree, then Rust makes that easy and obvious, whereas C++ offers you a hundred options, all of which suck.
reply
Isn't the obvious choice std::variant<>?

It is kind of annoying to use, but at least there is an obvious default choice.

reply
I take your point about it being the default, but IMO std::variant is pretty much unusable for a parse tree. It could work for small unions that you visit once in a while, but traversing a nested tree of std::variant types is just a disaster. It somehow manages to be comprehensively worse than using manually tagged unions in all aspects except safety.
reply