I've developed quite a bit in C, C++, Python, Go, Ruby, and Java/Coffee script and a hand full of others.<p>The thing is, of all the languages I code in C++ is my favorite. It is the most performant (using C where necessary), and is as easy to code in as JavaScript IMO. C++14 (and higher) feels like coding in Go or Python.<p>I feel most people don't actually have experience enough with modern C++ and are trying to use the 90's version of C++. The 90's version is awful, and even the modern has a few quirks. However, when you need performance and something less than C it's amazing.
I think there exists both necessary complexity and unnecessary complexity. Necessary complexity is when the underlying system is genuinely hard and trying to simplify it causes nuance to be lost -- Rust and Haskell are good examples. Unnecessary complexity just stems from poor design and then perpetually trying to add features on top of the poor design and making it worse -- the classic example is PHP.<p>IMO, C++ has <i>both</i> a lot of necessary complexity (due to its lofty goals) and a lot of unnecessary complexity (mostly due to the C back-compat). I think this is the root of a lot of the "C++ sucks!"/"C++ is great!" arguments; when people only see one half or the other.<p>My bottom line with C++ is that it tries and mostly succeeds to do a lot of hard things, but has questionable design decisions that make these things even harder than they need to be. For a while we just had to live with that because if you wanted a language that was both fast and high-level, C++ was the only game in town. I think that's no longer true, which is why I'm such a cheerleader for Rust: I see it as trying to have all the good things (necessary complexity) of C++ without the baggage.
This is myopic in the characteristically self-undermining way that most of these defenses are.<p>I actually like modern C++ well enough for the niche described here; lambdas (and the control they offer over captured variables), type deduction, ranged fors and the like make it pleasant enough to write for being as performant as it can be. I've written many more lines of C++ than Rust. But it's still apparent that language-enforced invariants are quite a different species from conventions that will enable safe programs <i>if</i> everyone uses them correctly at all times. You can <i>maybe</i> guarantee that for a team, but can you guarantee it for several teams? Can you guarantee it for every external dependency?<p>I can imagine plenty of pragmatic analyses today ending up with C++ as the ideal choice of language, but the monomaniacal focus on Performance ignores ecological concerns like these and also mostly doesn't grapple with the fact that there's plenty of low-hanging fruit to get to performance-wise in any project before something like a fundamental 1.2x performance penalty on Rust's part really matters, especially considering how domain-dependent that number is likely to be. Pure speed is a pretty poisonous obsession in our field, IMO, and I think we've reaped the whirlwind for it already. It's time for a more holistic outlook.
I work on high-performance scientific simulation software in C++, and, I have to say, it works really well for us.<p>Our competitors do a bunch of code generation to accomplish the same things in Fortran that we do with templates and policy classes.<p>Sometimes, for shits and giggles, I'll prototype algorithms in Haskell or Common Lisp or what have you and, I have to say, the experience isn't really all that compelling, and this is without introducing MPI and all the associated headaches of working with MPI in something it doesn't support first-class.
I found C++ very complex and difficult to work with, though it is very powerful in terms of performance. There is also several years of libraries available in C++ that is difficult to leave behind.<p>If you are looking for something like C++ in terms of performance and has a nicer syntax, you should try the D programming language. It's very nice to use, as fast as safe C++ code (you can write unsafe C++ that is faster), has stronger typing, templates, mixins, and can interface with C /C++ libraries.<p>I've moved my personal projects over to D, I've started writing a game with OpenGL, SDL, ASSIMP, Devil and it's much easier than C or C++.<p>Some links for those who are interested:<p>Main website: <a href="http://dlang.org/" rel="nofollow">http://dlang.org/</a><p>Package manager: <a href="http://code.dlang.org/" rel="nofollow">http://code.dlang.org/</a><p>Some interesting documentation pages:<p>Interfacing with C: <a href="http://dlang.org/spec/interfaceToC.html" rel="nofollow">http://dlang.org/spec/interfaceToC.html</a><p>Interfacing with C++: <a href="http://dlang.org/spec/cpp_interface.html" rel="nofollow">http://dlang.org/spec/cpp_interface.html</a><p>Templates: <a href="http://dlang.org/spec/template.html" rel="nofollow">http://dlang.org/spec/template.html</a><p>Inline Assembler: <a href="http://dlang.org/spec/iasm.html" rel="nofollow">http://dlang.org/spec/iasm.html</a>
I think C++ templates have hit a turning point where you can push much more static type information into your program and the compiler errors are increasingly useful.<p>For instance using the json for modern c++ json parser, you can write this:<p>myclass c = json_node;<p>and it compile time statically checks that a json->myclass deserializer exists, and gives sane errors if one of the (recursive) subfields of myclass does not have a json deserializer.<p>This makes json processing in python look like blood letting, and is close (until runtime) to the experience I'd expect from ocaml and other functional languages.<p><a href="https://github.com/nlohmann/json" rel="nofollow">https://github.com/nlohmann/json</a>
<i>Recent languages like Go and Rust have taken over a lot of mind share—at least on sites like Hacker News</i><p>C++ isn't "good" or "bad", it's just OLD (and is backwards compatible with an even OLDER language).<p>We are continually learning which language abstractions give a lot of implementation leverage (e.g. garbage collection), and which introduce unnecessary complexity.<p>Any new(er) language has the benefit of incorporating those learnings into the language design.
Gah, another one of those promotional posts about Rust.<p>More seriously, the large enough Noto Sans font with a hint of extra weight renders so gorgeous in Firefox (it's even bearable in Chrome!). I wish all webpages were as readable.<p>As for the content, well, going back to: <a href="https://eklitzke.org/c++-java-go-and-rust" rel="nofollow">https://eklitzke.org/c++-java-go-and-rust</a> I think the problem of the author is that he doesn't realize it's possible to do much better than C++. Claiming Rusts' ownership and borrow checking is exactly equivalent to std::unique_ptr or that Rusts' concurrency support is comparable to std::thread betrays very deep nativity, misunderstanding or just a mindset that can't see beyond what C++ offers.
Templates only generate maximally-efficient code in theory. Generality kills them in practice; or, it makes the template code twisted to the point of insanity. For example, there is <i>no</i> space-efficient way to model optional<T> for more than one value in a structure type; if you have several optional fields, it would make <i>much</i> more sense to be able to track optional state as single bits of one field (say) but the class structure <i>prohibits</i> such a space optimization and requires each template to track its own is-defined value. Pointless.<p>It is also essentially impossible to know that your code is well-tested: even when using something large and well-known like Boost, its authors <i>cannot</i> know what will happen when you substitute in 4 of your own types (my bet is “result not quite working as intended; obscure bugs added”).<p>I use templates but I am quite aware of code complexity and I essentially <i>stop</i> when the templating goes too far.<p>Somewhere along the line, we seem to have gotten into a mode of wanting generic code at all costs. Why? It is <i>just fine</i> to expose a few common specific methods when those are <i>very helpful and clear</i> (such as classes exposing a “string value”, “integer value” and “float value” instead of trying to provide some single partially-specialized template mess of a method that manages to <i>still</i> not quite work right in every scenario).
Is there a "c++: The good parts" ?<p>One of the projects I'm working on could have just as easily been written in c++ instead of go.. except that in go starting the project and building it involved<p><pre><code> mkdir my_project
# hack
go build
</code></pre>
I wouldn't even know where to start to write a simple c++ server that uses zmq and slings json around. How am I supposed to handle dependencies and vendoring?<p>As much of a PITA it is trying to learn rust, getting the toolchain working and starting a new project was not one of the issues I ran into.
From a practical point of view, in many cases the performance critical sections are tiny compared to the rest of the codebase. Imposing such a cognitive overhead on the programmer when 90% of the code are executed once a second just to make those 10% really really fast, and then screaming "performance!!!" is not very convincing. Just use a high-level language and drop to C when needed.<p>Anyway, the author later says he just enjoys writing low-level C++ code, however unpractical this may be. In which case I don't really see the point of defending his choice.
The point about templates being easy to optimize compared to other generics systems is simply wrong. Other generics systems provide more information to the compiler, so in addition to compiling faster and providing better error messages the compiler can use knowledge of specific type classes, interfaces, modules to optimize the implementation of. For instance, Rust can optimize `type NonZeroOption<T: NonZero> = Option<T>` to just the size of `T` because it knows that the `None` sentinel value is not used by `T`. You can also have nice features like GHC's rewrite rules which allow you to effectively tell the compiler how to optimize your types.<p>Most of the fast binary parts of templates is from stuff like specialization, which can be added to just about any generics system. Rust and Haskell both have it.
<i>This creates a feedback cycle where people are using C++ to get high performance, and that drives the language evolution towards confusing "features" (and idiosyncrasies) that are done in the name of making it possible to generate more highly optimized code.</i><p>You can replace C++ with <insert language here> and you can replace "language" with entire programming stacks. Large numbers of programming software toolsmiths have been laboring towards the wrong goals for the past few decades. We programmers are like old school computer hardware manufacturers hell-bent on delivering the highest spec numbers at the highest margins, while consumers were beset with poor quality, poor reliability, and experience degrading bloatware.<p>We programmers are particularly prone to inflicting ourselves with experience degrading bloatware, while ignoring our own particular human interface design needs. We need to stop emphasizing "sexy" things like raw performance and mathematically provable semantic guarantees and start looking at how we impact our experience while reading and debugging code. We need to start calling out toolsmiths who give us "power" at the cost of long startup <i>penalties,</i> and unresponsive, unwieldy software tools.
This article doesn't have a clue. For example:<p>> but many C++ programmers disable exceptions for performance<p>I have never seen a project like this for 10+something years. The only piece of code with disabled exceptions that I've seen was created for Atmel controllers. And in modern C++ exceptions is zero-cost. Your paying for exceptions only when they occur so, nobody is disabling exceptions now.<p>This is not the only line that bugs me but I don't have enough time for it right now.
It's hard to enjoy programming in C++ because the compile times are so long. C++ has grown up a lot, and smart pointers, a flexible template system, and lambda expressions, help you get a lot done easily, but every time you code up a useful abstraction, you risk ballooning your compile time.
> a rather weak type system, one inherited with relatively few changes from C<p>I don't understand this statement at all. C is a much weaker type system than C++. You can do things in C that will never compile in C++, it is much, much stricter.
> So if I try to use this template with the wrong type, after a bunch of template and macro expansion the compiler will print out a cryptic error showing the templated code and the failed type substitution.<p>This is one of the reasons why Andrew Sutton and Bjarne Stroustrup are trying to push C++ <i>Concepts</i> since C++11 [1]. They should provide much easier to understand compile time errors when it comes to templates.<p>[1] <a href="https://en.wikipedia.org/wiki/Concepts_(C%2B%2B)" rel="nofollow">https://en.wikipedia.org/wiki/Concepts_(C%2B%2B)</a>
C++ is an insanely versatile language, and since you can use any C library with "extern C", it has a huge amount of high-quality libraries available for it. ffmpeg, openSSL, webkit, Qt. the problem is there is not a cross platform package manager to manage these libraries, and manually downloading and compiling libraries is a hugely painful and error-prone process. it's so bad that big C++ projects like Firefox and Chromium basically write their own scripts that download and build dependencies, and simply commit the source code of the libraries they use directly into their own tree.<p>I believe there is some thought being put into making a C++ package standard [0], which would do wonders for the language. in my opinion half of the reason Node took off is because npm is so easy to use, and people are getting excited about Rust partially because Cargo is so well thought out. Now I might be wrong here, but I think if you took modern C++ (no raw pointer manipulation) and combined it with a good package manager, I think you would pretty much erase any advantages Rust offers.<p>[0]: <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0235r0.pdf" rel="nofollow">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p023...</a>
Aren't most of the points raised in the article actually solved by Rust? Doesn't Rust have a much cleaner template/metaprogramming system?
A few things:
1) Writing concurrent code in C++ is exciting (this is a bad thing). Processors are not getting much faster in serial execution, but the number of cores are continuing to increase<p>More here: <a href="http://joearms.github.io/2013/03/28/solving-the-wrong-problem.html" rel="nofollow">http://joearms.github.io/2013/03/28/solving-the-wrong-proble...</a><p>2) Programmer time is (usually) more costly than anything else in your organization. I'd argue that for most organizations, they're not making enough money per unit of throughput to justify the excessive programming time.<p>3) C++ is not designed for operators. Rust has this problem too. Once you know how to inspect a Java, Erlang, or Go program, the tools become familiar.
> <i>C++ is what you get when, at every turn in the language design road, you choose to take the path that leads to higher performance.</i><p>You have plenty of performance with C, and C++ is what you get when you enforce C compatibility at all costs, then tack on other stuff. The memory layout that classes and class hierarchies force upon you lead to sub-optimal caching behavior. Virtual functions don't have optimal performance, but they still made the cut. Pointer aliasing actually hurts performance as it prevents the compiler from doing optimizations.<p>I do agree with everything that was said in "The Joy Of C++", bonus points for acknowledging the Stockholm syndrome. However, pretty much all of it could be said about C.
> Templates are objectively extremely difficult to understand and use correctly<p>Really? Template metaprogramming is not the only use valid use of templates. Most time a simple <class T> is enough and that is already a huge improvement over C.
what is with programmers and needing to defend a combination of syntax, semantics, and runtime? C++ is a programming language with advantages and disadvantages. end of story.
Very close to my view.<p>Here’s my blog post about that: <a href="http://const.me/articles/why-cpp/" rel="nofollow">http://const.me/articles/why-cpp/</a>
Templates: originally for generics, now misused for SFINAE and slowing down the compiler.<p>Copy-elision: the copy constructor is unneeded, we should be move by default.<p>Answer: Rust.
I'm experienced in c++98.
I feel c++now is a new language full of weird syntaxes.
I mean, unnecessarily weird.<p>I don't know why so many languages support lambda nowadays.
It looks so weird and unnatural.<p>I still have to use c++ in some projects, never for the new syntaxes, just for there are some libraries I must use.
C++ is usually a premature optimisation.<p>I would use it for something like the Unreal game engine, because I know that:<p>- performance is important in much of the project<p>- the problem is complex enough to require high level language constructs<p>But for most tasks, my time would be better spent using a high-level language and then optimising the hot spots in, say, C.
In my humble opinion, after C++ 17, C++ does not need anyone's defense. I had worked on infrastructure pieces in Google and Facebook. Given the scale of data, and number of machines, it would not have viable without C++. Consider running 10 times faster using C++ still consuming thousands of machines that would have been 10s of thousands of machines. However, if your application runs fine using any slower language still consume single machine, it might not make sense in that case.
If you're starting a new system-level project, you should be using C++ or Rust, not C and <i>certainly</i> not Go (which was designed for kids to write microservices with; in other words it competes with Ruby and Node, not C++). A modern language should support static typing with parametric polymorphism and statically determined object extent for most objects (with well-defined extent for the rest). Rust also gives you statically determined object <i>access</i>.