It might be a good idea to compare C++ and Rust and not “C with Classes and no use of compiler options” and Rust. They do have a fair point about ugly template error messages, but the remaining issues are mostly moot: Freed memory issues can be avoided using std::unique_ptr and its siblings, lost pointers to local variables shouldn’t occur when using references instead of pointers, uninitialised variables are warned against when compiling with the (hopefully standard) -Wall -Werror, implicit copy constructors can either be deleted or this particular issue can be avoided by using a unique pointer (which has no copy constructor, hence the enclosing classes’ copy constructor is also deleted), I don’t quite get the issue with memory overlap, which is mostly an issue of a function receiving the wrong number set of arguments for the way it is written. The bit about broken iterators is actually nice, but in this case could be avoided by handing an external function two const_iterator which then cannot be changed. I don’t get the problems with "A dangerous switch" and "A broken semicolons", both seem sensible constructs and if you have bugs, you have bugs. Multithreading works as expected, except that using C++11 <thread> would probably have been nicer and one would have to explicitly make e.g. the lambda passed to std::thread mutable.
All in all, yes, Rust seems to be a nice language and in particular the template system looks somewhat more understandable, but please don’t write "Comparing Rust and C++" when you’re not actually using C++ but some weird mishmash of C and C++. If there are new, delete or pointer arguments in functions in your code, you’re most likely doing it wrong.
> Freed memory issues can be avoided using std::unique_ptr and its siblings
You can use a std::unique_ptr after it is assigned to something else. That's basically a use after free.
> lost pointers to local variables shouldn’t occur when using references instead of pointers
Lost references to heap variables happen all the time in C++ when the target is deallocated before the reference is accessed. It's the same problem and Rust fixes it the same way.
> I don’t get the problems with "A dangerous switch" and "A broken semicolons", both seem sensible constructs
Really? Then you're being naïve or obtuse. Both are common sources of bugs in C/C++. Accidental failure to handle all inputs (common when additional inputs are added after the handling code is written) and subtle typos with major consequences (see Apple's "goto fail" bug).
The purpose of Rust is to eliminate causes of careless and accidental errors by forcing you to do things the right way every time (rather than permitting lazy code).
> Really? Then you're being naïve or obtuse. Both are common sources of bugs in C/C++. Accidental failure to handle all inputs (common when additional inputs are added after the handling code is written) and subtle typos with major consequences (see Apple's "goto fail" bug).
I don’t know, it seems reasonable to me to allow switch() not to handle all possible inputs and/or fall through. Requiring for() loops to always have a body also seems unnecessary, there are cases where everything fits nicely into the three standard elements.
Rust allows you to not handle all possible inputs (but you must be explicit about it). If you look at the page again, you'll see "_ => 3", which is the rust version of a default case. This means that rust can tell if you if you forgot to handle a certain case.
As for the other things you list, I'd mark these more as "short-cuts", than features. It may take more effort to create code without them, but it gives parsing and code-readability improvements. Obviously the rust devs have made their decision here.
C++ is like a fairytale forest, where staying on the one safe path through the woods (unmarked, known only by whispered lore) will give you a reliable system, but where you are constantly tempted by easier-looking diversions at the end of which lurk grues.
And heaven help you if nobody has yet whispered to you the secret of the one safe path. Or if you consulted an older textbook, and the idiom it taught has a grue.
It's pretty well known that one should read Stroustrup's book and the Meyers books. If one were to learn in a vacuum, perhaps they would take a false path, but the community is in agreement on what the best learning resources are.
As cute as your comment is trying to be, most languages cannot be learned by blindly trying things out, one should actually read a few books, try to be a part of the community and so on.
There's no such thing as an agreement. Perhaps on the learning resources, but not about which features should be used, which I think it is a better interpretation of the parent's comment.
Take the C++ that's used on Chrome and compare to a Qt application. They'll be very different, and some features will be outright forbidden, depending on the codebase (for instance, Qt doesn't use copy constructors, or exceptions, and uses its own smart pointer classes). Not even templates, if you are using QObjects.
You not knowing anybody who uses RTTI doesn't mean much. I know people who use it. Our coding standard at work is mostly based on Meyers and Alexandrescu's guidelines.
Chrome and Qt's standards and design choices are their business and do not mean there is no recommended way to do things.
I am talking about Effective C++, More effective C++ and Effective STL by Meyers and The C++ programming language by Stroustrup.
Effective Modern C++ is about the new C++11 and C++14 standards. I am reading it now, looks good so far.
If you can get one thing, maybe Stroustrup's book would be the best choice, but make sure you get the latest edition which includes C++11. Note that amazon.fr has the kindle versions at significant discount (there's also a bundle of Meyers' first three books) if you are ok with their DRM.
I remember being a student and not having a big budget for books. Now I have a small apartment, and no space to put the books I have.
Abe Books ( http://www.abebooks.com/ ) provides a good place to look for used copies of books. A significant portion of the books in my library have stamps on the pages indicating that they were discarded from really nice institutions.
Of course there are always free-to-read blogs, but unfortunately, good C++ blogs are harder to find than other, newer language blogs.
> C++ is like a fairytale forest, where staying on the one safe path through the woods (unmarked, known only by whispered lore) will give you a reliable system, but where you are constantly tempted by easier-looking diversions at the end of which lurk grues.
Obviously it should warn you, but when one of the most popular C++ compilers has been failing to report uninitialised variables for 10 years then I think that the issue is worth raising. Clearly significant sections of the C++ community don't place a high value on the accuracy of these kinds of compiler warnings.
> The bit about broken iterators is actually nice, but in this case could be avoided by handing an external function two const_iterator which then cannot be changed.
No, I think you missed the point, which is iterator invalidation.
It's important to understand that various container methods can cause iterators to point to something else (or even nothing!).
In the example given, push_back could cause all the contents of the vector to be reallocated at a new address to make room for the new element. Any iterators pointing to the old address, including the one used in the for loop, don't get updated in this process.
In contrast, Rust only lets you have more than one reference to an object (like a vector and an iterator) if all of them are immutable. So any container methods that would cause iterator invalidation wouldn't be available inside of a for loop.
EDIT: Re-reading, I realize you might have already understood iterator invalidation, so sorry for the re-explanation, but I'll leave it up there for those that haven't heard of it yet.
I will point out that:
1. This sort of for loop is idiomatic C++ code.
2. C++ compilers don't even warn you when you push_back while having active const_iterators to your vector. Rust does, which is the point of the example. This is a case where C++'s const (logically won't change) is inferior to a stronger immutability guarantee, which Rust provides.
I'm aware of algorithms and espouse them, but you're not comparing apples to apples. The example is about mutating a collection while iterating over it:
...you could do that with std::for_each and a lambda, or maybe some creative use of std::back_inserter, but you'd still have iterator invalidation problems.
The right way to do it might be to use a while loop that uses std::find_if to find the next value to insert, but I'm not sure how you'd arrive at that solution without thinking about iterator invalidation in the first place.
...and the point is that Rust effectively says "you can't iterate over a mutable collection like that" while a less battle-scarred C++ developer might not even notice the problem before deploying to production.
Good points. Also, first paragraph says C++11 (too be honest, C++11 mode) yet first example has std::vector< std::vector <int> >::const_iterator. Where's auto, cbegin/cend ?
In short: none of the C++ code written in the article resembles what a well-trained, well-behaved C++ programmer uses. And the same cannot be said of the Rust code, I think.
On the other hand: maybe the whole point of the article is something like 'you don't have to be super well-trained in Rust yet won't shoot yourself in the foot'.
This is from Scott Meyers' new Effective Modern C++, in the chapter about why you should use 'auto'. Even the new 'safe' and 'convenient' features are loaded footguns.
Compilation-wise: of course not. As an illustration of what is wrong with the code: yes. auto means you don't have to spell out the complete iterator definition. cbegin\cend is just a matter of const-correctness.
> If there are new, delete or pointer arguments in functions in your code, you’re most likely doing it wrong.
Candidly, Modern C++ is an idiom adopted to work around the issues of raw memory management which Rust obviates out of the box.
What the author was writing was very standard introductory C++ taught in pretty much every C++ intro book I read in the early 2000s. That doesn't make it invalid C++, it makes it, "an older idiom".
To your more general point, C++ in the hands of an expert would clearly work better than presented here. I don't think that's an issue. The bigger question is, "Can C++ in the hands of a novice be as buggy as Rust in the hands of a novice".
> What the author was writing was very standard introductory C++ taught in pretty much every C++ intro book I read in the early 2000s. That doesn't make it invalid C++, it makes it, "an older idiom".
True. But that would suggest that we also consider Rust as it was taught in the early 2000s. I don’t think this would get us very far.
> The bigger question is, "Can C++ in the hands of a novice be as buggy as Rust in the hands of a novice".
Then it would be useful to firstly point out in the article that the matter of comparison is not the whole language but merely its usefulness to novices and to secondly consider the validity of such a comparison when deciding which language to use in a new project – if most people are novices for most of the time they use the language (e.g. in introductory numerical computing course), then clearly “novice friendliness” is a sensible measure, but otherwise it’s mostly a moot issue how hard the first two months are if you end up using it for the next ten years.
All in all, yes, Rust seems to be a nice language and in particular the template system looks somewhat more understandable, but please don’t write "Comparing Rust and C++" when you’re not actually using C++ but some weird mishmash of C and C++. If there are new, delete or pointer arguments in functions in your code, you’re most likely doing it wrong.