The main things that Rust offers over C++ are memory safety and better concurrency via data race freedom. There are other nice things too, like better macros, strongly typed generics, and pattern matching, but those two are the main highlights.
That being said, some projects are legitimately OK with some memory management errors and/or races creeping into production, in exchange for a lower learning curve in that area. If this describes your project, and you're happy with C++, then keep using C++.
(Note that I don't believe that "I write modern C++ so I never make memory management errors" is virtually ever true. Every large C++ app I've ever seen has fallen to some memory error or another. I think "I don't care (enough) about the errors" is a legitimate reason to use C++, but "I don't have to care" isn't.)
> Every large C++ app I've ever seen has fallen to some memory error or another. I think "I don't care about the errors" is a legitimate reason to use C++, but "I don't have to care" isn't.
I very much agree. Although few people would say "I don't care about the errors", out loud, even if that sentiment is valid in certain contexts.
In that light, I have a question for you: What other concurrency features does Rust offer over C++ outside of data race freedom guarantees?
Does C++ have the ability to safely share stack data without copying? I don't think so, but I'm not an expert.
Rust has a few libraries that enable stack-scoped threads that are safe by virtue of ensuring that all threads created in the scope terminate before the data they reference is dropped (EDIT: and by preventing mutation of shared state without guarantees about atomic operations).
For example, I'm working on a project that uses crossbeam:
Make the stack data const or wrap it in a mutex. That is what you end up having to do internally in Rust anyway, or being more sophisticated and having page locks.
Which requires the language to perform some kind of synchronization around the data access or you will have races between threads.
Just because you don't have to be explicit about it doesn't mean you don't need to have some mechanism to handle it somewhere, its just automatic instead.
> In that light, I have a question for you: What other concurrency features does Rust offer over C++ outside of data race freedom guarantees?
I would say that the biggest win of Rust, once you get past the data race freedom, is that Rust's overall design puts the CSP model front and center like Erlang and Go do, while C++ is built on mutexes, locks, and futures. The way to get started with concurrent programming in Rust is thread::spawn, Sender, and Receiver, which will take you far. But C++ doesn't even have channels in the standard library; it encourages you to dive headfirst into shared memory, which makes simple concurrency needlessly difficult.
Rust doesn't restrict you from using shared memory when you need to (and verifies that it's safe when you do). But Rust's libraries and ecosystem encourage you to design your apps in shared-nothing fashion first, and only to introduce memory sharing when you need it for performance. That's a much friendlier way to deal with concurrency than mutexes, locks, and futures.
That being said, some projects are legitimately OK with some memory management errors and/or races creeping into production, in exchange for a lower learning curve in that area. If this describes your project, and you're happy with C++, then keep using C++.
(Note that I don't believe that "I write modern C++ so I never make memory management errors" is virtually ever true. Every large C++ app I've ever seen has fallen to some memory error or another. I think "I don't care (enough) about the errors" is a legitimate reason to use C++, but "I don't have to care" isn't.)