
In Defense of C++ - eklitzke
https://eklitzke.org/in-defense-of-c++
======
lettergram
I've developed quite a bit in C, C++, Python, Go, Ruby, and Java/Coffee script
and a hand full of others.

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.

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.

~~~
mschuetz
C++11, 14 and 17 finally made me fall in love with C++. It's almost like
having a nice and easy scripting language with the added bonus of static
typing and a huge performance boost.

There are a few things that I'm still not quite happy with.

* It's still incredibly cumbersome to set up a project

* Setting up a proper build system is tedious, especially if you're targeting multiple platforms.

* I'm missing some "functional" methods attached to the collections, e.g. find, filter, map, some, each, ... Afaik some of them exist as functions that take 2 iterators and a lambda but that's just plain ugly and unreadable. Instead of
    
    
        std::find_if(list.begin(), list.end(), condition});
    

I'd like something like

    
    
        list.find(condition);

~~~
sqeaky
Have you tried CMake for setting up you C++ projects? It hide pretty much all
the dirty details of find libraries and linking against libraries.

If you already have a compiler installed, you can go from nothing to knowing
how to build a library, executable and an installer for multiple platforms in
just a couple of hours with the CMake tutorial: [https://cmake.org/cmake-
tutorial/](https://cmake.org/cmake-tutorial/)

~~~
chairmanwow
I agree that CMake is better than handwriting a Makefile, it is still
absolutely shit compared to Rust's build system or the straightforwardness of
sourcing external dependencies with Maven or Gradle in Java.

If I want to use an external library in a C++ project, I need to:

* download it from the website / GitHub

* build it from source

* add the library into my CMake file.

Whereas in Gradle, I add a single line to one file and the library is
installed on my next build attempt. Full stop. There are no more steps.

C++ makes it searingly painful to get a project going. I'm honestly afraid to
add any new libraries to my projects because I know that (at minimum) that
means I'm sacrificing an afternoon to resolving new errors.

~~~
btschaegg
Although I generally agree with you (CMake is a pain), I wouldn't say that
this problem is caused by the language itself.

That you have to compile anything yourself is a byproduct of the fact that
different platforms have different ABIs, combined with the lack of proper
package management on platforms like Windows.

What I find the most enervating about CMake is that somehow everyone agreed
(at least to some degree) to use the worst cross-platform build tool in
existence. Instead of a build system based on solid principles we got a "hack
your own build" starter kit in which you have to look for dependencies
yourself ^1 combined with a build script language that is worse than the
languages it set out to replace. How can anyone honestly be happy when
switching from makefiles to this monstrosity?

^1 And no, the FindX scripts never work properly everywhere.

~~~
Arizhel
Personally, I agree about CMake and its horrible scripting language, and I
like Scons a lot more. It's Python-based so it's easy to work with and
flexible, and not nearly as ugly as CMake.

~~~
sqeaky
I think CMake took off, because it has no dependencies, works with any IDE and
can be extended to do anything.

I have been in places where demanding python just wouldn't work. Either a
specific version was needed for something else and managing the dependencies
was a pain or we were already reliant on other scripting languages. I think
this kills any other language as a build tool.

There are zealots for every IDE and some IDEs require special project files.
If your build system doesn't seamlessly integrate most then it couldn't have
made it. Scons never worked with IDEs I liked, Know how to get it cowkring
with QtCreator? Other will demand vs2015r3 integration, how do you do that?

Then then there are the build systems you didn't mention, but the minimalistic
ones. There was even one that was entirely stateless, but it was also too
inflexible for most real builds.

CMake very carefully walked a thin line that dodged all these issues and the
fact it is a giant pile of global mutable shared state simply doesn't for all
but the largest builds.

------
Analemma_
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.

IMO, C++ has _both_ 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.

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.

~~~
stcredzero
_IMO, C++ has both 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._

C++ is more like an ecosystem of about a dozen languages. You can divide it
into 4 languages chronologically. You can add a lot more by categorizing by
use. If you pick and choose properly, you can set up a subset of C++ that
makes it a _great_ language. Half the computer programming managers out there
have below average taste, however.

~~~
gcp
Any sufficiently large project that pulls in dependencies will likely involve
you dealing with all 4 of them.

This is one reason why I doubt _adding_ more features to C++ (making it 5) is
going to make the language any more pleasant to use (outside toy, one person
programs).

~~~
stcredzero
_Any sufficiently large project that pulls in dependencies will likely involve
you dealing with all 4 of them._

Which describes my current work situation. However, this would seem to imply
that a startup or a small project would be able to set up a C++ project with a
beautiful, cohesive subset of C++. Your point is something that people who are
serious about language design for programming "in the large" should definitely
pay attention to.

 _This is one reason why I doubt adding more features to C++ (making it 5) is
going to make the language any more pleasant to use (outside toy, one person
programs)._

How do you distinguish between one, two, three, or four person projects? Can
you really make such a blanket statement about all the different possible
codebases that exist? Methinks you exaggerate.

(And I say this as a former dyed-in-the-wool minimalist Smalltalker!)

~~~
gcp
I put the distinction at "more than 1" because that's the point where you need
to deal with code that isn't your own.

(In theory of course your buddy could use a style and feature-set really close
to your own and make it all a nice abstracted API so you don't need to look
inside etc, but you get my point)

~~~
stcredzero
_I put the distinction at "more than 1" because that's the point where you
need to deal with code that isn't your own._

You've never worked in a small shop where there was a good coding standard and
everyone stuck to it? That sort of thing actually does pay off. I've seen this
in my professional life.

~~~
gcp
We tended to use libraries or external dependencies, too.

(And when that was out of the question, C++11 and later usually were as well)

~~~
stcredzero
You should be able to build facades around that stuff, so your main codebase
is all C++11.

~~~
pjmlp
That doesn't scale in big code bases, or in the typical corporate culture.

~~~
stcredzero
I know for a fact this isn't necessarily true.

~~~
pjmlp
I don't mean it never works, just that is it seldom the case.

I know C++ since the C++ARM days, it is one of the languages I like most
despite its warts, teached it to first year students before C++98 happened.

Nowadays I spend my work hours in Java and .NET stacks, but still do
occasionally use it, when needed.

I never worked in a company, with exception of my time at CERN, that actually
followed C++ best practices.

So yeah, there are lots of companies making good use of C++, as proven by
CppCon and C++Now talks, but they seem to be the minority, when you take into
consideration the ones whose main business is not selling software.

At least I was pleased to see the BMW presentations at FOSDEM, where they
mentioned moving from C to C++14, as a means to improve safety on car systems.

~~~
stcredzero
_So yeah, there are lots of companies making good use of C++, as proven by
CppCon and C++Now talks, but they seem to be the minority, when you take into
consideration the ones whose main business is not selling software._

I should be more thankful about my current job, then. I guess a good heuristic
for judging a language is to go to conferences and see what is portrayed
there, then "dividing by 8." That will get you to about the level of the
average shop.

------
mrbrowning
This is myopic in the characteristically self-undermining way that most of
these defenses are.

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 _if_ everyone uses them correctly
at all times. You can _maybe_ guarantee that for a team, but can you guarantee
it for several teams? Can you guarantee it for every external dependency?

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.

~~~
pjmlp
As example, I never had any issue with bounds checking being enabled in all
languages I used through my career.

Even in C++, I always had bound checking on my own classes and always make use
of the validation flags in VC++.

It never mattered to the type of applications I was involved with.

~~~
anonymoushn
I spent some time working on HFT systems. These things needed to achieve end-
to-end timings (from a tick being DMAed into our memory to placing an order)
around xx microseconds at the 99th percentile. The bulk of the code was
written in a language that forced us to have bounds checking everywhere, and
that was totally fine.

~~~
yxhuvud
I'd assume most array boundary checks can be optimized away by a good compiler
anyhow, assuming the array semantics allow that in the language in question.

------
neutronicus
I work on high-performance scientific simulation software in C++, and, I have
to say, it works really well for us.

Our competitors do a bunch of code generation to accomplish the same things in
Fortran that we do with templates and policy classes.

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.

~~~
ziotom78
I used to write scientific code in C++ too, but since a few years I've
switched to Python+Fortran using f2py to automatically create bindings.
Although there are a few drawbacks (different conventions in indexing arrays
is the most annoying), I have not regretted this decision, python's ecosystem
is incredibly large, and Fortran plugging Fortran modules allow me to optimize
both speed and memory consumption efficiently. (But I eagerly await for the
day Julia will be mature enough to allow me to switch!)

I only use Fortran just for low-level number crunching, and I must say I have
yet to miss C++ templates here for this kind of stuff. I'm curious, what is
your typical use of templates in your simulation code?

~~~
neutronicus
> what is your typical use of templates in your simulation code?

Apart from templating over floating-point precision, we use templates and
policy classes to do a lot of the code reuse / flow control you'd use run-time
polymorphism for, but without the overhead of virtual function calls. This is
pretty useful for us, because our simulation algorithm has a lot of sub-parts
that can be done in different ways. Rather than having a bunch of switch
statements (or virtual function calls) in inner loops, we can have that switch
statement once, in a factory object, and return instances of objects templated
over the correct policy class so that we don't have to branch in inner loops.

One of our main competitors is on the Fortran / Python plan. Our application
has, instead, a few proprietary input formats (one XML-ish, and the other
binary to be used with a GUI). This has its drawbacks (i.e. rolling and using
our own Python-based macro language for use with the XML-ish input files). The
CEO tells me, though, that this is actually kind of a godsend from a support
perspective, because there is a point where all of the customer's simulation
logic is frozen into a text file, which we can then debug (this is in contrast
to the Python / Fortran approach, where the customer's simulation logic may be
very tightly coupled with our own code).

------
chhs
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.

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.

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++.

Some links for those who are interested:

Main website: [http://dlang.org/](http://dlang.org/)

Package manager: [http://code.dlang.org/](http://code.dlang.org/)

Some interesting documentation pages:

Interfacing with C:
[http://dlang.org/spec/interfaceToC.html](http://dlang.org/spec/interfaceToC.html)

Interfacing with C++:
[http://dlang.org/spec/cpp_interface.html](http://dlang.org/spec/cpp_interface.html)

Templates:
[http://dlang.org/spec/template.html](http://dlang.org/spec/template.html)

Inline Assembler:
[http://dlang.org/spec/iasm.html](http://dlang.org/spec/iasm.html)

~~~
RobertDeNiro
How easily can you use D on something that's not x86? Is there decent cross
compilation?

~~~
chhs
I've not used D on platforms other than x86 but I have heard cross compilation
mentioned in the comments of some conference talks. I found this page which
has the status of the LDC compiler on various platforms. It looks like it is
still under development but I don't know recently that page was updated.

Status of various platforms:
[https://wiki.dlang.org/LDC](https://wiki.dlang.org/LDC)

------
hedora
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.

For instance using the json for modern c++ json parser, you can write this:

myclass c = json_node;

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.

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.

[https://github.com/nlohmann/json](https://github.com/nlohmann/json)

~~~
WildUtah
C++ type inference and first class lambdas and flexible typed tuples have made
it possible to create a real useful type system into C++ programs now. It's
quite pleasant.

But it robs a lot of much slower languages of their best value proposition.
You can now do it all in C++ with correctness guarantees and still run 10x
faster than most strong typed systems.

~~~
gpderetta
> C++ type inference

we prefer to call it type deduction not to upset type theory purists.

~~~
WildUtah
Steve Miller and Don Henley seem like such easygoing guys on stage. Surely the
purists aren't so touchy.

------
payne92
_Recent languages like Go and Rust have taken over a lot of mind share—at
least on sites like Hacker News_

C++ isn't "good" or "bad", it's just OLD (and is backwards compatible with an
even OLDER language).

We are continually learning which language abstractions give a lot of
implementation leverage (e.g. garbage collection), and which introduce
unnecessary complexity.

Any new(er) language has the benefit of incorporating those learnings into the
language design.

~~~
WildUtah
_a lot of implementation leverage (e.g. garbage collection)_

Putting garbage collection in that basket is controversial and lately the
evidence is piling up against it.

Notice how new important growing languages like Swift and Rust don't have
garbage collection and programmers don't miss it. GC is more and more
restricted to low performance languages like Python, Javascript, and Ruby and
a few specialized highly tuned and expensively engineered exceptions like the
JVM and obscure LISP engines.

And if you've ever tried to program responsive, interactive, predictable, or
time-critical systems, you know that GC is ruinous and awful for those
applications. Meanwhile languages like Rust, Swift, and C++ can be used for
everything from systems programming to games to low power mobile apps to
scripting.

~~~
david-given
Swift does have garbage collection! It uses reference counting, and AFAIK it
doesn't have cycle detection, which means it's up to the developer to ensure
that no cycles occur.

Regarding responsive interfaces: pure reference counting is particularly
problematic for this, because an unbounded amount of work may happen every
time an object's reference is decremented (because the object might be freed,
which causes other objects' references to become zero, etc). If this happens
inside a critical section Your Life Is Pain. At least you can control when
this happens by taking and then dropping an additional reference. (See Obj-C's
allocation pools.)

C++'s shared_ptr<>, BTW, is also reference counting, and suffers from the same
problem. So it's technically correct (which is the best kind of correct) to
say that C++ has garbage collection too.

~~~
WildUtah
Reference counting isn't garbage collection. It's the opposite of garbage
collection. With reference counting, which is optional in C++ and can be opted
out of in Swift, you keep track of your allocations and release them when
you're done with them. With garbage collection an outside program decides when
you're done with memory and deals with it for you on its terms.

It's true that there can be unlimited work done in reference counting. Of
course, it's true there can be unlimited work in any function of any program.
[0] With reference counting a programmer can fix the amount of work to be done
and when in deterministic fashion. With garbage collection, there is no such
power. The gc decides when it will work and you cannot control or predict the
interruption.

You cannot produce serious interactive or time sensitive control software like
that. You certainly can't write system software like that.

[0]
[https://en.wikipedia.org/wiki/Halting_problem](https://en.wikipedia.org/wiki/Halting_problem)

~~~
pjmlp
> Reference counting isn't garbage collection.

Reference books in computer science, acknowledged by the experts in the field,
happen to disagree.

[http://gchandbook.org/](http://gchandbook.org/)

~~~
khedoros1
How about: Reference counting is one form of garbage collection, but "Garbage
Collection" without any additional qualifiers or context usually implies
"tracing garbage collection", with or without the aid of other GC algorithms.

In common usage, I don't hear of languages like C++ described as a "garbage
collecting language". That usually describes Java, Python, etc.

~~~
pjmlp
C++ has a GC API and a few dialects that support GC like C++/CLI.

Having RC library types doesn't make a language GC, because their correct use
is not enforced by language semantics.

------
gcp
Gah, another one of those promotional posts about Rust.

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.

As for the content, well, going back to: [https://eklitzke.org/c++-java-go-
and-rust](https://eklitzke.org/c++-java-go-and-rust) 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.

------
makecheck
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 _no_ 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 _much_ more sense to be able to track optional state as
single bits of one field (say) but the class structure _prohibits_ such a
space optimization and requires each template to track its own is-defined
value. Pointless.

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 _cannot_
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”).

I use templates but I am quite aware of code complexity and I essentially
_stop_ when the templating goes too far.

Somewhere along the line, we seem to have gotten into a mode of wanting
generic code at all costs. Why? It is _just fine_ to expose a few common
specific methods when those are _very helpful and clear_ (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 _still_ not quite work right in every scenario).

~~~
Animats
_Somewhere along the line, we seem to have gotten into a mode of wanting
generic code at all costs._

I know. Years ago I proposed a vector library for 2, 3, and 4 element vectors
[1] as a standard. The immediate complaint was that it didn't use templates.

[1]
[http://www.animats.com/source/graphics/algebra3.h](http://www.animats.com/source/graphics/algebra3.h)

~~~
slavik81
The trouble is that a reasonable requirement such as single-precision floating
point support would require a developer to copy/paste/modify hundreds of LOC.
The choice is really fork, duplicate or template.

I don't blame glm for picking the latter. Every option is painful, but
templates might be a little less so.

------
justinsaccount
Is there a "c++: The good parts" ?

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

    
    
      mkdir my_project
      # hack
      go build
    

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?

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.

~~~
sien
Have you read Effective C++ & More Effective C++?

That's a start for what you want.

~~~
lj3
I think you mean "Effective Modern C++". The two you mention predate C++11.

[https://www.amazon.com/Effective-Modern-Specific-Ways-
Improv...](https://www.amazon.com/Effective-Modern-Specific-Ways-
Improve/dp/1491903996/ref=pd_bxgy_14_3?_encoding=UTF8&psc=1&refRID=CJT3K27NC7A692DCXP46)

------
pka
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.

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.

~~~
panic
But once you've optimized those sections, the rest of the performance problems
are left scattered through your code. I've had to rewrite a system in C++ just
a few weeks away from shipping because even after optimizing all the
performance-critical sections, we still needed that extra 15% or so of
"ambient" performance.

~~~
pka
Sure, then you have a valid use case for C/C++ (even better, Rust!) But often
people don't and still use C++.

------
bbatha
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.

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.

~~~
dbaupp
I don't think the T: NonZero bound is doing anything there: the size
optimisation is done on the monomorphised/specialised type, not the generic
one. In Rust, the concept of a generic types only exist at compile time, and
they have no layout. Of course, this is still an example of a generic systems
that specializes for performance, in a language that isn't C++.

------
stcredzero
_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._

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.

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 _penalties,_ and
unresponsive, unwieldy software tools.

------
chaotic-good
This article doesn't have a clue. For example:

> but many C++ programmers disable exceptions for performance

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.

This is not the only line that bugs me but I don't have enough time for it
right now.

~~~
panic
There are reasons to disable exceptions aside from performance. Google's C++
style guide (which bans their use) discusses some of the pros and cons:
[https://google.github.io/styleguide/cppguide.html#Exceptions](https://google.github.io/styleguide/cppguide.html#Exceptions)

~~~
chaotic-good
I saw this first time many years ago. It clearly states that exceptions is a
good thing but shouldn't be used in Google's projects because their code is
not prepared for exceptions:

> On their face, the benefits of using exceptions outweigh the costs,
> especially in new projects. However, for existing code, the introduction of
> exceptions has implications on all dependent code. If exceptions can be
> propagated beyond a new project, it also becomes problematic to integrate
> the new project into existing exception-free code. Because most existing C++
> code at Google is not prepared to deal with exceptions, it is comparatively
> difficult to adopt new code that generates exceptions.

And most importantly, I don't think that they're disabling exceptions using
compiler flag. I'm sure that they just using error codes for error handling
instead of exceptions.

------
lostdog
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.

~~~
TillE
Yeah, this is the genuine pain point experienced by actual C++ developers.
Though really only templates will kill your compile times; other modern
features are pretty safe. Modules will help. Hopefully.

------
hellofunk
> a rather weak type system, one inherited with relatively few changes from C

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.

------
vmarsy
> 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.

This is one of the reasons why Andrew Sutton and Bjarne Stroustrup are trying
to push C++ _Concepts_ since C++11 [1]. They should provide much easier to
understand compile time errors when it comes to templates.

[1]
[https://en.wikipedia.org/wiki/Concepts_(C%2B%2B)](https://en.wikipedia.org/wiki/Concepts_\(C%2B%2B\))

------
symlinkk
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.

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.

[0]: [http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2016/p023...](http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2016/p0235r0.pdf)

~~~
cousin_it
Does this one-liner count as modern C++?

    
    
        const string& s = max<string>("a", "b");
    

It makes a dangling reference that will crash when accessed. In Rust that's
impossible.

~~~
symlinkk
good point, I had never heard of that.

------
amelius
Aren't most of the points raised in the article actually solved by Rust?
Doesn't Rust have a much cleaner template/metaprogramming system?

~~~
Manishearth
Note that Rust's system is a generics system, and there's less metaprogramming
that can be done by it. Namely, the property mentioned in the post where "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." does not exist in Rust,
since you specify bounds in the API itself.

This is both a blessing and a curse. As a blessing, it leads to very neat,
clean, APIs and you never have to worry about such template expansion errors.
As a curse, some of the more complex bits of C++ metaprogramming (check out
what people achieve with SFINAE) are not possible. I personally think the pros
outweigh the cons, but many people from the C++ world really like the power of
template metaprogramming in C++. Rust is planning on offering procedural
macros which address some of the use cases, but not all.

------
petters
One huge advantage of C++ is Visual Studio. Once Rust gets something similar I
might switch for my personal projects.

~~~
flukus
Doesn't VS only support a really old version of c++?

~~~
pzone
No, they keep up pretty well with the C++ spec.
[https://blogs.msdn.microsoft.com/vcblog/2016/01/22/vs-2015-u...](https://blogs.msdn.microsoft.com/vcblog/2016/01/22/vs-2015-update-2s-stl-
is-c17-so-far-feature-complete/)

You may be thinking of the lack of full C99 support.

------
sargun
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

More here: [http://joearms.github.io/2013/03/28/solving-the-wrong-
proble...](http://joearms.github.io/2013/03/28/solving-the-wrong-problem.html)

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.

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.

~~~
Const-me
First, OpenMP isn’t that bad. Second, the author of the article you’ve linked
forgot about another kind of parallelization, SIMD. Realistically, SSE and AVX
instructions are only usable from assembler, C, C++, and Fortran.

Sometimes throwing hardware at problems don’t work. Either because it’s
technically impossible (console games, mobile) or because you don’t own the
hardware (PC games, desktop software). For such products, either you spent
“excessive programming time” programming C++, or you won’t release any product
at all.

------
ndh2
> _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._

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.

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.

~~~
lossolo
> The memory layout that classes ... force upon you lead to sub-optimal
> caching behavior.

Simple classes have the same memory layout as C structs, contiguous chunk of
memory which means they are cache friendly.

~~~
ndh2
No, they're not cache friendly. The problem is row-based vs column-based.
Array of structs vs Structure of arrays. With arrays of structs/objects you
get row-based access patterns. Especially for cases where you only want to
access one or two columns, you always pull in everything else.
[https://www.youtube.com/watch?v=rX0ItVEVjHc](https://www.youtube.com/watch?v=rX0ItVEVjHc)

~~~
corysama
Are there any popular languages that support SOA 1st-class? C++ is largely
competing with GC languages where it is difficult to avoid separated heap
allocations for every tiny bit of data.

~~~
nicwilson
While not 1st class, in D you can do a completely transparent library
solution, because you can introspect the fields of the struct you want to be
SoA and insert arrays of those fields in to the SoA'd type.

Á la
[https://github.com/economicmodeling/soa](https://github.com/economicmodeling/soa)

------
netheril96
> Templates are objectively extremely difficult to understand and use
> correctly

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.

~~~
rubber_duck
Even most meta programming is not extremely difficult, unless we're talking
boost level stuff, and more importantly it allows you to do super powerful
interfaces for your API that are trivial to use (the implementation might get
complex but consumption shouldn't be).

Like say you have a collection of entities where each entity can have one or
more components of different types. Now you want to find all entities with
components A, B, C and the returned value should have typed references to
components - it gets a bit hairy to implement but it's trivial to use and
efficient.

------
jfe
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.

~~~
pessimizer
> C++ is a programming language with advantages and disadvantages. end of
> story.

Sounds like the beginning of a story, during which you explain the advantages
and disadvantages, determine where C++ is best used, and compare it to other
options.

------
retrogradeorbit
AFAIK C++ still doesn't have a finally construct for its exceptions. Are there
any plans to introduce it? Is so, when does it land?

~~~
sandeatr
C++ does not need finally, so it would not make much sense to add it. RAII is
superior and is what is used instead.

Finally would likely just encourage people to write really awful C++ code.

~~~
retrogradeorbit
So are you saying that C++ has no plans to implement finally?

(also I totally disagree that RAII is superior to finally. Finally, being
lexically scoped, is far simpler, far shorter and far easier to understand.
[https://codecraft.co/2013/10/31/why-we-need-try-finally-
not-...](https://codecraft.co/2013/10/31/why-we-need-try-finally-not-just-
raii/) )

~~~
sandeatr
That article does not convince me, scope guard + lambda appears to work just
as well as finally, and is actually shorter(see tianyuzhu's comment)

I do not know if anyone has proposed it for C++, but I would be surprised if
it passed given that it doesn't accomplish much.

------
jwatte
C++ is called a "bad" language by people who think go or JavaScript are "good"
languages.

------
Const-me
Very close to my view.

Here’s my blog post about that: [http://const.me/articles/why-
cpp/](http://const.me/articles/why-cpp/)

------
ishitatsuyuki
Templates: originally for generics, now misused for SFINAE and slowing down
the compiler.

Copy-elision: the copy constructor is unneeded, we should be move by default.

Answer: Rust.

------
tapirl
I'm experienced in c++98. I feel c++now is a new language full of weird
syntaxes. I mean, unnecessarily weird.

I don't know why so many languages support lambda nowadays. It looks so weird
and unnatural.

I still have to use c++ in some projects, never for the new syntaxes, just for
there are some libraries I must use.

~~~
tdsamardzhiev
Lambdas give you a (somewhat) saner syntax for

1\. Defining a function within a function.

2\. Capturing a function call for later use.

~~~
tapirl
Couldn't it be some less weird, just like the anonymous functions in
JavaScript and Go? Even the lambda in Java is much readable than c++.

It give me the feeling that, c++ gives every corner a special syntax, or c++
adds new features by adding new syntaxes, there is no the word "reuse" in the
process of improving c++.

In go, anonymous functions and general functions and methods have no much
differences. But in c++, lambda and general functions and class methods are
too different. Using class methods as callback in c++ is awful.

C++1x features make c++ code less readable, for fewer and fewer programmers
know every syntax corners in c++.

------
Pitarou
C++ is usually a premature optimisation.

I would use it for something like the Unreal game engine, because I know that:

\- performance is important in much of the project

\- the problem is complex enough to require high level language constructs

But for most tasks, my time would be better spent using a high-level language
and then optimising the hot spots in, say, C.

~~~
joejev
> \- performance is important in much of the project

At scale this always becomes true. C++ can be written with reference counting
and other high level concepts with runtime penalties. When you need to
optimize or scale, you will never need to look to another language. I do a lot
of numerical computing in Python and often need to drop into Cython or C; in
C++ this wouldn't need to happen. One the the main goals of C++ is that "there
is no language below C++".

High level language constructs are always nice, and C++ has a lot of "zero-
cost" abstractions, meaning you only pay for what you need. For example, an
iterator in C++ can just be a raw pointer in the case of iterating over a
vector, but it is more complicated for a std::map because it is backed by a
tree. C++ is a high-level language, so I don't understand the argument that
you would be better off splitting your stack between the "important" parts and
the slow parts.

~~~
harry8
Overstated. There is a level below c++, namely assembly intrinsics. When it
comes to simd code using sseN avxN you really do use them when performance is
important. That's if you're staying on the CPU. Going massively parallel on a
GPU? FPGA? C++ isn't as low as you go.

~~~
MaulingMonkey
I'd have more time to optimize at these lower levels if I wasn't stuck
babysitting C++ codebases to protect them from and fix their undefined
behavior.

------
herewhere
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.

~~~
sqeaky
"Need"... I hope.

We could make that sentence damning or glorifying, depending on the missing
word choice and someone would argue with you about it, no matter what word.

------
bitwize
If you're starting a new system-level project, you should be using C++ or
Rust, not C and _certainly_ 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 _access_.

~~~
microcolonel
How can you, knowing absolutely nothing else about the use case, suggest a
solution? What if they're on an architecture where the libc++ or rust runtime
is low quality? What if their application needs to be NUMA aware?

There are plenty of reasons not to use C++ or Rust. They are not magic bullets
which solve all engineering challenges.

