Rust's memory model is even more familiar to C++ programmers who don't manage memory by hand because they have the same concepts of borrowing and lifetimes.
I was just trying to find a modern C++ tutorial, but there's nothing comparable to the Rust Book on the internet.
I think even now the best resource to learn C++ is to first learn C, then original C++, then all the modern memory management techniques, which is just crazy hard for a new programmer compared to just going through the Rust book 10 times (which is needed to get a deep understanding).
Professional C++ is the 1072 page book that taught me modern C++, for what it's worth. I have the physical copy. And even then I have gripes with some of it's contents! The Rust book is second to none, tbh, and I say this as someone who doesn't really write Rust.
As someone who wrote C++ for 20 years, just don't. It's a horrible language(s). None of the codebases look the same, everyone uses different features or different versions of the language. Building is a nightmare, it takes forever to do anything. Run!
I know this is an unpopular opinion but if you want to stick with C++, the solution to this, at least in my experience, is to stop doing things that let you shoot your foot off. C++ gives you every tool in the tool chest, and most of them are not safe. Stick to a safe subset and you've solved 90% of all those stereotypically C++ problems.
I've got a pretty big C++ codebase for my hobby projects, sanded down, polished and perfected over the years without the usual corporate pressure to ship. The few times I run into memory corruption, a memory leak, a segfault, dereferencing a shit pointer, undefined behavior, and so on, its always, always because I'm doing something I shouldn't be doing. Like working with raw pointers or pointers to pointers to pointers, or traversing an array of bytes to do something there's already a library that does, or manually calling delete on something, or using reinterpret_cast<>, or using one of the many footguns C++ happily gives me. The simple key is to just stop doing these unnecessary things.
Yes, but "just don't do that" doesn't scale to large teams with varying levels of experience and discipline. It sounds like you have rules that even you disobey on this project.
Everything you said is true. C++ gives you everything you need to be safe. But that's not the point.
Rust makes it HARD (or very hard) to do things that are unsafe.
It's not what C++ can or cannot do, it's not what Rust can or cannot do. It's what the Rust language and compiler opinionatedly encourage you to do and not to do. This is what's lacking in C++.
I think many people - me included - are complaining that it makes things hard period. Not in the sense of “rocket science” as this argument is sometimes smugly dismissed, but in the sense of extra friction which slows things down and decreases the pleasure of coding.
> The few times I run into memory corruption, a memory leak, a segfault, dereferencing a shit pointer, undefined behavior, and so on, its always, always because I'm doing something I shouldn't be doing. Like working with raw pointers or pointers to pointers to pointers, or traversing an array of bytes to do something there's already a library that does, or manually calling delete on something, or using reinterpret_cast<>, or using one of the many footguns C++ happily gives me.
You've never used an out-of-bounds index? Accidentally used an object that was on the stack beyond the function call? Let an integer overflow? The problem with C++ is that all of these things don't look like unsafe operations, and people end up making mistakes with them that are not obvious.
> You've never used an out-of-bounds index? Accidentally used an object that was on the stack beyond the function call? Let an integer overflow?
Can't speak for the OP, but I never see any of these bugs in my C++ code. You can write code with these bugs but that is more of a style choice, practically speaking. The C++ bugs I see are almost always in complex state logic or in rarer cases an unexpected/unhandled error case from a call to outside code, which can happen in every language.
When using GCC for example, there’s a macro one can define which adds bounds checking to all containers.
Integer overflow can be turned into defined behavior through a compiler switch.
Holding pointers to stack variables past the return is not as easy to inadvertently do as an off-by-one. Someone has to store the address into a variable and this kind of code should raise alarm bells.
A more indirect way is to pass an address of a local variable to a function which is typical. But then if a function takes arbitrary pointers it receives and stores them, this should also raise some alarm bells.
The most recent example I debugged for a colleague was a container of callbacks, and one of them ended up changing the container while it was being iterated over. Nothing crazy, just no easy way that we were aware of to catch that kind of thing.
Yes, of course. If you use C++, try to not shoot your foot off. The same advice also applies to Rust or any other programming language. You should still try to follow best practices and not mess up, even if a language makes it less likely to mess up in certain ways.
The question is how often you mess up in each language and how bad those mess-ups are. This depends a lot on the programmer(s) and the kind of project. My personal view is that the space of team/project combinations where you should ever start a new C++ project is now confined to "team desperately wants C++".