top | item 2548480

The Dark Side of C++ (2007)

76 points| KonradKlause | 15 years ago |fefe.de | reply

53 comments

order
[+] dkarl|15 years ago|reply
Again the operator overloading thing.

Yes, it's true. && might do something different than you might expect if you're a C programmer. If you're a C++ programmer, then you know somebody might have overloaded the && operator. Yes, they could do it in some weird and unexpected way. Just like somebody can declare a weird and unexpected macro in C.

Yes, people who define C++ classes you use can screw you with dangerous or incorrect behavior, like throwing exceptions from destructors. Just like people who write C libraries can screw you with dangerous or incorrect behavior.

auto_ptr is not useless. At least, I assume it's good for something. Who knows? If not, who cares? boost::shared_ptr is "poor man's garbage collection," not auto_ptr. If you cite the documented behavior of a type as a huge and unwelcome surprise, then gosh, I know exactly how to avoid surprises like that: read the freaking documentation before you use the type.

Oh, and again with the "I can't tell what this code does." Here's a crazy scenario in C: call a function. Do you know what the code does? No, you don't. How awful! Unless you look at the function you just called, or maybe just glance at its documentation.

Half of these criticisms of C++ boil down to, "It's okay for functions to have unknown behavior that I have to learn about before using them, because I'm used to that, but it's not okay for types to have any kind of unknown behavior, because I'm used to C, where that is not the case."

[+] coliveira|15 years ago|reply
> It's okay for functions to have unknown behavior that I have to learn about before using them, because I'm used to that, but it's not okay for types to have any kind of unknown behavior, because I'm used to C,

It is not an issue of behavior but of understanding.

In C++, a large number of things can be happening in a single line: an operator being called, a type conversion, a template instantiation, an overriden function in one of a dozen of classes, a constructor called in some part of the hierarchy, in some namespace... who knows. You have to be smart enough to figure out what is going on in each of these cases. As you code base grows, this makes it increasingly hard to understand what is going on.

[+] dzorz|15 years ago|reply
Actually you can't overload && although you can overload &.
[+] rgarcia|15 years ago|reply
I have to disagree with some of the "warts":

operator[] adds a member to a map if it does not already exist

The main theme of this article seems to be "C++ gives you too much flexibility," but this is a case where C++ is enforcing a default behavior and limiting your flexibility. In Python, for example, understanding code that queries for a key in a dictionary requires you to know some context about whether that dictionary has a default value for missing keys. For all the quibbling the OP does about operator overloading, I'd expect him to be grateful for the predictable nature of map's operator[].

local static initialization is not thread safe

This is just wrong: http://stackoverflow.com/questions/1270927/are-function-stat...

[+] comex|15 years ago|reply
Huh? The standard behavior in Python is to throw an exception if the key does not exist.
[+] thedigitalengel|15 years ago|reply
Firstly, half of the time the guy bitches about flaws with the compiler, and not the languages (Page 0 to 6).

Most of the bitching is about language features which exist. If you don't like auto_ptr then DON'T use auto_ptr! C++ at least allows you to ignore features without paying a penalty. Which is why it has a virtual keyword; and does not make every method virtual like Java.

The at() versus operator[] is also an example of the above: bounds checking can get expensive in a tight loop.

It seems that the author has never seen a large, well-written C++ project. In fact, that is the case with many such C++ bashers (I used to be one too). Once one sees how C++ makes it easy to manage a 500000 line project, they will probably think again.

[+] Raphael_Amiard|15 years ago|reply
> Firstly, half of the time the guy bitches about flaws with the compiler, and not the languages (Page 0 to 6).

That's pretty unfair. It's the language's complexity that makes the compiler task almost impossible. Before clang came around, most C++ compilers had really shitty error messages, gcc, icc, and microsoft's indiscriminately.

[+] KonradKlause|15 years ago|reply
> It seems that the author has never seen a large, well-written C++ project.

I doubt that, I suggest search a bit for his name and find out what he is doing for a living...

[+] Peaker|15 years ago|reply
Many good criticisms, mixed with some bad.

Exception safety is achievable (pthread_mutex_lock example) if you wrap resources with RAII classes. If he called this "difficult to use C libraries while retaining exception safety" it would be more accurate.

The iterator criticisms are applicable to C iterators too (represented by pointers or user objects).

The various things `baz = foo->bar(3)` could mean are interesting. Some of them are reasonable, if you assume some sort of consistency. It may make audits hard, but the fact it might use implicit cast converters there should not make it harder to read if you are allowed to make the most basic assumptions about what an automatic cast operator would do.

I enjoyed it, nonetheless.

[+] andos|15 years ago|reply
Some of the examples at the end are laughable.

    If new[] throws an exception, this leaks 
    a file handle and deadlocks the next caller.
Poorly written code is buggy? No shit, Sherlock! — to paraphrase the OP.

The Frequently Questioned Answers has good, insightful criticism of C++ is here: http://yosefk.com/c++fqa/

[+] comex|15 years ago|reply
> With C++, you don’t see the writes, because it says `some_func(whatever,the_int,SOME_FLAG);` and it can still write the_int if it’s a reference. In C, it would be &the_int, which is easily recognizable.

I don't understand why people do this. C++ has not abolished pointers; it's still possible to require the &, and it increases readability considerably; why ever use references (to value types; objects are different) as function parameters?

[+] arghnoname|15 years ago|reply
reference to const gives the benefit of passing a pointer, efficiency wise, but prevents the called function from modifying the contents it points to.
[+] huhtenberg|15 years ago|reply
I tend read all "C++ is (bad|good)" lists and it never occurred to me to look at operator overloading as something inherently bad, something that sacrifies the clarity of the code for its brevity (see page 23 and onward). This is an excellent angle... but not that I would prefer C++ to not support overloading.
[+] albertzeyer|15 years ago|reply
Many of the complaints have become irrelevant or at least much less relevant with C++11 and huge progress also on the compiler side (most notable clang but for example GCC also has improved many of the unreadable error messages).
[+] Jach|15 years ago|reply
I don't use nightlies, but last time I checked even clang didn't have great template error messages. C++11 doesn't address his complaint of ever-changing standard (though I don't think that's really serious). Does C++11 support lazy extensions? (Last I checked it didn't. Use case: "Unless someone declared operator&&, then both are evaluated.")

I think most of the complaints are still valid even with C++11. Whether the complaints are worth bothering about is another issue: C++ is hard, yeah, it's not going to get easier. Personally I wouldn't ever start a new project in C++, I'd rather use C or Go or Obj-C if I need low-level speed and there's a plethora of high level languages (that can still connect with C if needed) if I don't. I nevertheless have to know C++ (non-11) for all the older projects out there, most of which probably won't move to standardize on 11 making 11's benefits moot.

[+] comex|15 years ago|reply
Has it? The other day, the latest MacPorts gcc46 gave me:

warning: format '%d' expects argument of type 'int', but argument 2 has type 'std::_Hashtable<std::pair<unsigned int, unsigned int>, std::pair<const std::pair<unsigned int, unsigned int>, GraphNode>, std::allocator<std::pair<const std::pair<unsigned int, unsigned int>, GraphNode> >, std::_Select1st<std::pair<const std::pair<unsigned int, unsigned int>, GraphNode> >, std::equal_to<std::pair<unsigned int, unsigned int> >, std::hash<std::pair<unsigned int, unsigned int> >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, false, false, true>::size_type'

After a quarter century, is it really that difficult to use the type I wrote rather than this hideous expansion?

[+] gchpaco|15 years ago|reply
C++11 has made things more complicated, not less. All these criticisms are still valid and can be extended with some added new stupidities (for example needing to explicitly specify capture in lambdas, a new and entirely unique way to shoot yourself in the foot; or user defined numeric literals which brings the joys of parsing C++ down the stack making even tokenizing it difficult).
[+] dhruvbird|15 years ago|reply
> Iterator to stale element (resized vector, or balanced tree after rebalance)

I don't think that rebalancing the tree invalidates iterators (other than the deleted element [if any] that is)

[+] Groxx|15 years ago|reply
After seeing some of those rants, especially after the namespace-hatred, I wonder if they'd prefer a flavor of Assembly. Apparently they hate many common methods of simplifying and organizing code - clearly, things like virtual methods should always look different than non-virtual methods, namespaces are pointless when you can `gl_open`, and all macro-like functionality is simply obfuscation.
[+] jfr|15 years ago|reply
Most, if not all, of his arguments were already beaten to death. The rebuttal should be floating around somewhere on the Internet, but I couldn't find it with a quick search right now.

Anyways, right at the beginning of the presentation you see the quality of his arguments as he uses a very known problem of a particular compiler (GCC) to bash the language. Sort of a straw man fallacy.

[+] kjksf|15 years ago|reply
His argument is that C++ is so complex that it's extremely hard to write a fast, reliable compiler that generates good error messages.

The fact that it took gcc programmers 10 years to get to a point where gcc doesn't use ridiculous amounts of memory when compiling few lines of tricky code is a fact in favor of the argument, not against it. Gcc programmers are smarter than an average programmer. If it was easy, they would have gotten it right on the first try. Accordingly, C or Java or C# or Go compilers didn't have such problems so C++ is more complex for compiler writers than pretty much every other known language.

The same goes for error messages. In the past decades we've had tens of C++ compilers. If clang is the first one that is able to generate decent error messages for templates, then it means it was a hard problem to solve.

None of that got any easier: if you want to write another C++ compiler, it'll still be hard for you to generate decent error messages or compile tricky C++ code reasonably.

[+] KonradKlause|15 years ago|reply
Very sad, you have read only the first few slides...
[+] dhruvbird|15 years ago|reply
> x[0] -= x[1]; // x[1] adds sizeof(bar) here, not sizeof(foo)

This code doesn't even compile?? What is the author trying to show with this example?

[+] mattgreenrocks|15 years ago|reply
Please flag this article. Why do we feel the need to discuss how much C/C++ rocks/sucks repeatedly? HN should frown upon bikeshedding more than it does.

If I wanted an echo chamber, I'd be on Reddit.

[+] nasmorn|15 years ago|reply
Very true. I don't think articles like this fall under pg's definition of deeply interesting. They always draw crowds though. When I see one I have to summon all my strength not to read it.