6 ms·
In my experience, the opposite of what the author claims is true: modern C++ leads to code that's easier to understand, performs better and is easier to maintai
by jupp0r 10y ago
In my experience, the opposite of what the author claims is true: modern C++ leads to code that's easier to understand, performs better and is easier to maintain.
As an example, replacing boost::bind with lambdas allowed the compiler to inline functor calls and avoided virtual function calls in a large code base I've been working with, improving performance.
Move semantics also boosted performance. Designing APIs with lambdas in mind allowed us to get rid of tons of callback interfaces, reducing boilerplate and code duplication.
I also found compilation times to be unaffected by using modern C++ features. The main problem is the preprocessor including hundreds of thousands of lines for a single compilation unit. This has been a problem in C and C++ forever and will only be resolved with C++ modules in C++2x (hopefully).
I encourage the author to try pasting some of his code into https://gcc.godbolt.org/ https://gcc.godbolt.org/ and to look at the generated assembly. Following the C++ core guidelines (http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines) is also a good way to avoid shooting yourself in the foot (which is surprisingly easy with C++, unfortunately).
- blazespin 10y agoI think the author was mostly referring to meta programming / templates. You have to admit, they can get pretty obscure sometimes. I agree, lambdas simplify callbackas/async programming immensely.
- TillE 10y agoRight, but there's nothing "modern" about templates. Those have been a disaster for compile times forever. C++98 with no Boost is an awful language that nobody should want to go back to. It's one where you could legitimately prefer C99, despite its lack of RAII and other conveniences. Actual modern C++ is a great language to write, though the compile times haven't really improved.
- moron4hire 10y agoGiven the position that system quality is directly proportional to frequency of testing, in what ways can a C++ project from-the-ground-up mitigate compile times and be reactive to change?
- vinkelhake 10y agoFully agree with what you're saying. Just a nitpick about bind (which I'm sure you're aware of, just for the sake of others). The return type of {boost,std}::bind is unspecified (it's basically just a "callable"). This means that bind doesn't have to do type erasure. On the other hand, {boost,std}::function has to do type erasure, which can boil down to a virtual function call. But that's orthogonal to where the callable came from. Another thing to keep in mind is that if you're writing a function like `copy_if` which takes a callback, but doesn't have to store it for later use, it's much better to take the callback as a template type rather than going through the type-erasing {boost,std}::function. Doing the latter makes the compiler's job a lot harder.
- deleted 10y ago[deleted]
- plorkyeran 10y agoIt's not type erasure per se, but it's somewhat functionally equivalent. When you pass a function pointer (or pointer to member function) to bind(), it has to store that pointer in a member variable and perform an indirect call in operator(). In theory this is something that a compiler should be able to optimize away, but in practice they very rarely actually do, so using bind() as the argument for a STL algorithm typically does not result in the whole thing getting inlined out of existence. Lambdas, OTOH, are super easy to inline out of existence and compilers actually do so most of the time.
- vinkelhake 10y agoNote that I'm not advocating bind over lambda. I'm saying that one shouldn't expect a boost in performance when switching from std::bind to lambda. Switching from std::function to a templatized "Callable" could give a boost in performance, but like I said, that's orthogonal to how the callable was created. There really is quite a difference between what std::bind returns and a type-erasing class like std::function. For the latter, the type erasure may result in a virtual call that the optimizer has a hard time seeing through. In practice, compilers are pretty good at optimizing bind. Here are some examples where lambda and bind generate identical code: https://godbolt.org/g/dQCSeG https://godbolt.org/g/dQCSeG
- plorkyeran 10y ago> As an example, replacing boost::bind with lambdas allowed the compiler to inline functor calls and avoided virtual function calls in a large code base I've been working with, improving performance. And not just runtime performance; IME replacing bind() with lambdas typically significantly improves build time performance significantly. C++03 with C++11 features emulated via library trickery has terrible compile times compared to having the same features built in to the compiler.
- namelezz 10y ago> In my experience, the opposite of what the author claims is true: modern C++ leads to code that's easier to understand, performs better and is easier to maintain. Can you comment on the memory safety of modern C++? I am wondering if I should learn Rust or modern C++.
- PeCaN 10y agostd::unique_ptr, move constructors, etc and you're pretty safe, but it's still not in the same league as Rust. In my opinion you should probably learn Rust unless you want to get a job writing C++ (e.g. game development).
- pcwalton 10y agoI never quite understood why unique_ptr and move semantics are supposed to improve memory safety over new and delete. They reduce leaks, sure, since the compiler inserts free for you at a hopefully-useful place. But you still effectively have to decide when to free, and there is no protection against dangling iterators, references, or pointers. From a security point of view, use after free is far worse than leaking, since UAF can lead to remote code execution. In fact, move semantics create a new type of hazard that wasn't in earlier versions of C++: dereference of a unique ptr after moving it.
- gpderetta 10y agoThey do help somewhat by making ownership more explicit, i.e. they are hints that the programmer can use to do the kind of analysis that rust would do automatically. Dereferencing a moved-from unique_ptr is UB, but many compilers do abort in their hardened modes. edit: spelling
- lbrandy 10y ago> I never quite understood why unique_ptr and move semantics... It's not those types, in particular, it's because C++11 allows you move your ownership model into the type system. And then, and this might sound familiar, writing code cognizant and explicit in its ownership semantics leads to safer, cleaner code.
- roel_v 10y ago"The main problem is the preprocessor including hundreds of thousands of lines for a single compilation unit." Some code bases have no real way around that, but many are served well enough with precompiled headers.
- bogomipz 10y agoQuestion - is it possible to just learn the new modern C++? How does one do that with a language that has been around for over 30 years? Can you just learn C++11? Don't you come across all kinds of code bases and texts that span many different versions that you have to be able to reason about? I mean certainly this is true of Java as well but I would like to hear other's views.