69 comments

[ 3.0 ms ] story [ 115 ms ] thread
C++ is a language that's easy to code badly in, but that doesn't mean it's hard to code well (portably, maintainably, effectively) in.

IMO it's a language that well suits pragmatic programmers who are willing to cherry-pick the most convenient and productive features for their projects and leave the rest alone.

It's a terrible language for those of us who compulsively try to be clever and use every little nook and cranny of the language they're using. They get lost out in the dark scary corridors and spiderwebs, and then say "C++ sucks" instead of "what the hell, don't go out there unless you really NEED variadic templates today."

Edit: And it's easy to get yourself in really weird pickles if you don't know what not to do, (static initialization order, I'm looking at you!) I've found my WTF-per-minute rate has dropped dramatically over the years as my coding style has improved.

This comment reminded me of a lesson in The Elements of Programming Style:

Use good language features, eschew the bad ones (paraphrased).

After reading this, some opinions across a few languages made more sense. For example, Crockford advocates subsetting, hence JS The Good Parts. There are also more times than I can count where choosing a subset of C++ from its stupendously large array of features.

When you think about it, it's possible to write esoteric, hard to read code in many languages, even ones designed to improve programmer productivity. If a language offers you capabilities that can blow readability out of the window, you'll see it happen. The more capabilities for such and the larger the number of programmers using the language, I'm sure you'll see a larger number of cases where code is indecipherable.

From experience, to finish, I've seen a lot of very straight-forward C++ code that shines with readability compared with some Python code I've come across.

> C++ is a language that's easy to code badly in, but that doesn't mean it's hard to code well (portably, maintainably, effectively) in.

It kinda does. It's like Perl: between the historical precedent, the stuff that's available on the interwebs, the affordances of the language and the easiest/shortest way to solve a given problem, it's way harder to code portably, maintainably and effectively than not, and you need to expend serious efforts trying to keep up. Which most people aren't going to do.

It's the old quip that "within C++, there is a much smaller and cleaner language struggling to get out". If you have the knowledge and the discipline you can use that smaller and cleaner language, but I don't think you can argue it's easier to use that smaller and cleaner language than to use C++ in general.

Yes. C++ used to be my favorite language. I still like it a lot, but I no longer love it.

The trick, in my opinion, to C++ was what you were not doing. Coding in such a rich language means making a lot of decisions up front about limiting complexity. That turns out to be a good thing.

The reason it's not my favorite anymore? Because the language designers seem hell-bent on continuing to make it more and more feature-ful. Over time, it's creating a huge, diverse codebase, all with the title "C++ code" on it, but all vastly different in nature and scope. That ain't a good thing.

STL is a good example. On its own, STL is a good thing. Greatly needed in the language. But now that its implemented, its basically its own system. You could solve world hunger with STL (I am being factitious to make a point) Remember the criticism Microsoft always had, that they couldn't build anything that did just a few things? Everything had to be able to do everything? C++ has that, only worse.

I like the language. I really do. I don't know if I've given up on it -- unless I wanted to tweak the hell out of something or was writing lower-level code the answer is probably "yes" -- but it seems to be heading in a direction that is not good for the maintenance programming community. It's great for really smart people who love complex things, but no so much for the poor schmuck coming in 10 or 15 years later. It's become a monster.

I'm not sure why you say that about the STL - you didn't give any examples.

Having worked with it a large amount at this point it seems to me to be mostly very well designed and focused on fundamentals of the parts of a program that are both common and non trivial.

Some things are messy (like hashing) some things are missing (like serialization) and some things would be incredible to have (like thread local heap allocation, lock free concurrent data structures, some sort of dynamic stack allocation, the functionality of something like capnproto, shared memory and memory mapping...), but in general it seems like it covers the fundamentals well.

> It's a terrible language for those of us who compulsively try to be clever and use every little nook and cranny of the language they're using.

Do you mean the Boost developers? :)

Right now, C++ is less portable than Java..., that really have this ‘write once, run everywhere’ thing.

As someone who's currently rewriting a massive Java project in C++ so we can port it to other platforms, this made me laugh.

It reminds me of that physicist joke about spherical cows. "Assume a working JVM..."

I have the migration studies for a big software base containing C++ code, Ada code and Java code (around 30% each). The migrations were from HPUX to RedHat4, then to RedHat5, then to RedHat6.

Each time, more than 90% of the migration workload was on the C++ code.

Maybe that's because C++ was used mostly for system level calls, and low level jobs.
One advantage of Java is huge standard library with basic support for important OS-specific things like filesystem, threading, GUI, time, etc. You don't get all the bells and whistles of your OS, but you can write portable code which works and does some simple things expected to be possible "everywhere".

C++ only recently is starting to go there.

Interesting. Is that still the case if you go in with the intention of writing portable code, though? Or was it just a case of taking a large single-platform piece of code and porting it?

The main issue is that Java's portability has hard limits. C++'s may require work, but it is at least (in theory) almost always possible.

I have the migration studies for a big software base containing C++ code, Ada code and Java code (around 30% each). The migrations were from HPUX to RedHat4, then to RedHat5, then to RedHat6.

Each time, more than 90% of the migration workload was on the C++ code.

The fun of C++ portability starts when one needs to make the code portable across multiple compilers instead of the usual gcc, clang and msvc.

Java was an welcoming bless when it appeared in terms of code portability. Writing portable C++ code in the days of pre-ANSI C++98 was a mess.

A classic case of "there is an exception to every rule" - sure, if your target platform has no JVM then you are screwed, but how often does this happen for projects where Java is well suited? (e.g. Please, do not answer with "well, we have an embedded platform" .. This is simply not what Java - today - is build for, despite the fact that it began as a language for embedded devices a long time ago)
If C++ is really so portable, then why don't you just compile openjdk to your other platforms instead of rewriting all the Java code?
C++ is the new Cobol
Nah, PHP is the new COBOL
Nah, Java is the new COBOL. Billions of LOC that will never be replaced, running on arcane infrastructure. In this case the arcane infrastructure isn't mainframe hardware or OSes, it's J2EE bean containers, XML configged ORMs, and Ant build systems.
You are right, of course. Maybe PHP is the new VB?
(comment deleted)
Man I am so glad I escaped all that. Sheer luck !
One of the best things about Java is that getting old code running on newer hardware is so much easier compared to the COBOL cluster-fuck we have these days. Hopefully we won't see as much 30+ year old hardware running our mission critical Java applications as we see our COBOL applications.
I do like C++, but I do find myself more and more finding bugs that would have picked up in another language.

"Huh. I'm pretty sure Rust would have picked me up on that bug."

Here's an example. I accidentally wrote this:

    while (getLine(pc, buffer, sizeof(buffer) > 0))
Which compiles fine. Stricter languages could detect this bug.
Most likely two bugs. The bracket one, and the fact that sizeof(buffer) will give you the pointer size, not the buffer size if buffer is a pointer rather than an array.
The first one would be caught in Rust as it has no integer -> boolean automatic conversions (similar to Java).

The second one could only arise with unsafe pointers in Rust, as safe code uses slices, combining the base pointer and the element count in a single value.

> The second one could only arise with unsafe pointers in Rust, as safe code uses slices, combining the base pointer and the element count in a single value.

OTOH the point here is to pass a preallocated but "uninitialised" buffer to the callee, which Rust wouldn't allow with slices, unless you created a slice from a raw allocation (I don't know if that's defined behaviour, though I guess you could do that safely by passing in a Write rather than the slice itself, but then you're Write-ing to a slice which has… interesting behaviour)

Your second point depends, in fact, on whether buffer was allocated statically.
Er, no.

   #include <stdio.h>

   static char buffer[80];
   static char *bufferp=buffer;

   int main(int argc, char *argv[] )
   {
	char localbuffer[80];
	char *localbufferp=localbuffer;
	printf("buffer: %ld\n",sizeof buffer);
	printf("bufferp: %ld\n",sizeof bufferp);
	printf("localbuffer: %ld\n",sizeof localbuffer);
	printf("localbufferp: %ld\n",sizeof localbufferp);
   } 
Output:

   marcel@sarek[tmp]./a.out 
   buffer: 80
   bufferp: 8
   localbuffer: 80
   localbufferp: 8

As you can see, it depends entirely on whether you give sizeof the array or the pointer.
`buffer` was indeed an array, not a pointer. The bug was the bracket!
Most compilers should give a warning about this.

Of course warnings work until you have source from something external that throws lots of warnings that you can't reliably turn off (possibly due to completely broken and ignored warning bugs in ICC for example).

I am interested on your views about Portability. While Boost and STL are portable in terms of static compilation Boost gives you very painful bugs at runtime :(. I also would like to know why you say that Java is portable on paper ?
I've used parts of boost extensively on embedded platforms and cross-platform projects without ever encountering painful runtime bugs. What issues did you have?
(comment deleted)
"I agree it’s complicated, but that’s not necessarily a bad thing. You really don’t need to understand the whole thing to start using it. And when you’ve been using it for a while and start to understand the intricate details, it becomes very, very powerful."

To be honest, this is a corporate sales pitch. It's trying to justify the injustifiable

It doesn't need to be full of "features" that most people don't use. Granted, some of them are needed regardless

C++11 and 14 have simplified some parts, which is good. Still, a lot of other languages do more with less complexity

Some things that are painful

- String formatting in STL is a joke

- "Smart pointers" are still an add-on and clunky to use

- No reflection. Manual setup of getters/setters/copy constructors

To be event more honest, everything is complicated when you do not master it. C++ is a language with true benefits in terms of execution speed and flexibility, it may not just be the language for everything and everybody.
You can get most of the speed with C and it is not as complicated

Flexibility should not imply in being "hard to use"

Thats an old sentiment that apparently never goes away, just like C++ is "hard to use", its only hard to use because you dont know what you are doing, when you are using C++ professionally you get to learn the language and appropriate patterns and after a while your perfectly comfortable, just like you would be with Java, Go, Haskell and Lisp.
What's wrong with std::string though?
Compared to how strings are handled in many other languages or libraries, std::string is pretty limited. It works, though, and I use it. But when you have to do something basic like a trim, you find yourself wondering why it's not included.
What isn't?

Without boost::format and boost::algorithm, std::string is a major pain in the ass to work with. Even including those two, there's still the distinct lack of unicode-awareness (and no, wstring doesn't help, and neither does "let's pretend it's all utf8 underneath".) And then there is the institutional problem that nobody agrees on whether, and if so how, to use std::string in their libraries' API's.

But on the bright side, string handling in C++ is not as painful today as it was in 2005, things do get better.

I'd argue that a mutable by-value string type is not suited to most applications, hence why many other languages have avoided providing that style of string type as their core string type.
unique_ptr is easy, no overhead, and its friend, make_unique(), allows for concise generation of the smart pointer. what's clunky about that? (of course, make_unique didn't appear until C++14, so it was a bit more clunky before that).
I've been having so much fun writing functional programs in C++14 after spending 2 years writing exclusively Clojure code. It was amazing to me that I could return to C++ and use most of the same idioms and styles that I'd gotten spoiled by in Clojure. The ability to pass and store anonymous functions, with captures when desired, is so useful, and doing this is easy in C++11/14. It has really changed my appreciation of the language. The algorithm library for doing things like map, reduce-style expressions is also wonderful. C++ is a rapidly moving target and they are not resting on the past.
This could be a blog post ;) What compilers do you use?
I use clang. There are a number of good c++ bloggers out there, so not sure I'd add anything worthy to the mix.
I meant the "write C++ like Clojure" part! That transition ain't common, AFAIK.
I've given up on finding another C++ programming job for the foreseeable future. The problems I have is not with the language itself it is the other C++ programmers I have issues with. Not to say that I don't think the language doesn't have issues. With proper care you can work around the issues and avoid overcomplicating the code. But occasionally you have other C++ programmers who just makes things too complicated and don't realize that they have done so.
In my personal experience, C++ suffers from a surfeit of programmers who don't have a perspective on just how unproductive C++ is, and fall into the trap of considering themselves as an elite based on the complexity of their language of choice. I'd recommend C++ programmers learn how other languages have moved far beyond C++ in usability, because that will help them in writing C++.
Can you give an example of a language that goes beyond C++11/14 in both speed and usability, including tools?
(comment deleted)
Well in part I agree. That is why I've expanded my language toolbelt over the years. I just have yet to meet any smug C++ weenies, I only occasionally see them in comments on the internet.
It's interesting to not consider a language based on what you want to write, but what you wish the other person had written it in.
Well for personal projects I choose my tool myself and I'm open to use C++, it is going to be my code. But doing it for a living and cooperating with other people... I prefer use other tooling.
I've heard that "people can write bad code in any language", and always assumed that it was true. Do you have experience with other languages/ecosystems where that isn't true? If so, which one(s)?
I haven't found a language which can't be abused. But I have found that C#/.NET and Python has many straight forward solutions which its users gravitate towards. So it is more about that how the programmers in the ecosystem behave that is my main issue.

One anecedote is: "I know I'll use one of the Curl++ wrappers instead of using the normal interface, because C" ... "But this wrapper throws exceptions in the destructor, that is bad and leads to 'interesting' debugging sessions" ... "but C!".

Something that throws an exception in the destructor? And people want to use it anyway?!? That's enough to make you want a different ecosystem, all right...
It is an anecdote of things I got tired of. Another one is the return of reference for "performance". I pass around this link each and everytime. https://en.wikipedia.org/w/index.php?title=Return_value_opti...

And other numerous of other small gripes... I'm familiar with some of the dusty corners of C++ and I have to constantly educate people about them.

In a way I have plateaued with C++, almost too comfortable with it. I need to do something else.

My own take on the original article that this author is responding to:

>C++ IDEs suck. Big time.

I find Xcode quite a pleasure to use. The autocompletion, debugging, the quick moving around the interface, splitting files side-by-side.. I haven't used other IDEs besides emacs, but nothing about Xcode is getting in my way.

>It’s an unmanageable language.

Compared to a dynamic language or a weakly-typed language (I'm looking at you C, and a few others), I'd say the strong typing of C++ alone helps in code manageability. And, unlike Swift or Clojure or other languages, I find putting an API in a header file and an implementation in a translation unit really helps me reduce time later on. It's an automatic API summary without needing to review your implementation. When I move on from one part of a program to another, I don't want to study my source code just to remember what the access is. Just show me the header. I miss header files in other languages.

>It’s a counterproductive language.

and

>STL sucks.

The tools in the STL are serious time-savers. Sure you can choose not use them or implement your own, but in either scenario, you will likely spend a lot more time writing code than working on your actual problem or idea. In that regard, I'd say C++ and its standard library are very productive. And all the new multithreading and async primitives in C++11/14 take this productivity to a new level.

>namespace stupidity

Without namespaces, you have to work harder to name your stuff and to debug name clashes. Every good language that I've worked with uses namespaces. I consider them a requirement for any language that will handle a large project.

>The language sucks. It sucks because it’s so complicated.

C++ is probably the most complicated language I will ever use. I'm not sure why that makes it suck, though. Unlike many other languages, where it is wise and expected that you can keep the whole language in your head and understand entirely how it works, C++ is a different thing altogether. Nobody on this planet probably understands 100% of C++ -- including its creator, who has said that he gets maybe 80% there. In C++ you can use a small and ordinary part of the language and choose to go to the complicated stuff only if you really want to, but rarely do you need to. Yes, complex metaprogramming is mind-bending in what you can do -- and also, you cannot do a lot of it any other language. But you don't have to do any of that, and most people probably shouldn't, until they want to have some fun and really see how deep C++ can go. And a lot of the most complicated stuff that was important to understand in the past is no longer required reading for new programmers to the language, since the latest standards handle many things for you automatically. I.e. just writing "new" or "delete" and deciding when and how to do so are no longer required and actually discouraged thanks to smart pointers.

Yeah, STL is a good thing about C++. It might have its problems, but in general it's more good than bad
> I find putting an API in a header file and an implementation in a translation unit really helps me reduce time later on. It's an automatic API summary without needing to review your implementation. When I move on from one part of a program to another, I don't want to study my source code just to remember what the access is. Just show me the header. I miss header files in other languages.

`make doc` (maybe as part of your build process even), then view the autogenerated API documentation. This is at least a feature or extension of most languages. C++ even has a number of documentation suites (e.g. Doxygen, IIRC).

Furthermore, if you're using a "good" IDE, I would expect it to be able to provide you the same basic information you get from header files (i.e. method signature & names). It could at the very least have a "collapse function implementations" hotkey to allow you to view a source file as if it were essentially a header file.

I don't know, the fact that it's somewhat trivial to actually generate a .h file given a .c or .cpp file (look up LZZ - Lazy C++; it's not maintained, but it did exactly this) makes them seem pretty much useless to me.

C++ is fool's gold.

Its complexity is inefficient and this gives the sensation of power and accomplishment, when all we have done is waste energy on translating abstract thought into a fragile foam of symbols. Then finally there is a sad degree of orthogonality between the meaning and structure of said foam and our original thought. But it sure feels like we did something. We slaid that dragon good eh!

Most C++ IDEs have problems, probably because C++ is a difficult language to fully parse. I’ve only ever used Visual Studio and KDevelop.

That's me, about seven years ago. Then I tried Qt Creator. Now I'm an evangelist. It just works. It parses all your code in seconds and you get autocomplete and syntax coloring that's very close to perfect. The interface is as clean as it gets. And yes, you can use it without ever touching Qt (the framework) at all.

The only thing is, try to avoid versions > 3.2.2 since they are a bit buggy.

Edit: fixed typo.

I want to use QT Creator but I find some things frustrating such as finding out how to change compiler options in a reliable way. Sometimes it is QMAKE_CXXFLAGS or some other option in the .pro file. In every other IDE it is a tick box in project settings. Yes yes I know a tick box sucks but it sure makes things easier to remember how to do rather than yet another cryptic bit of text in a config file, I have enough of that anyway.
This can be avoided by using CMake as QtCreator supports it as a project type. CMake isn't exactly a bastion of simplicity however.
To be honest I am just very lazy and would appreciate a simple GUI to make the build and project files. I guess Visual Studio has made me lazier ;)
It's easy to bash anything, to find only bad things in something. And to let go, give up and get frustrated and write blog posts like this.

Sure, most of this stuff is correct, like the header madness, but still C++11 especially is pretty nice these days. There just isn't any other way to do cross-platform, performant code, while having the compatibility with all the C/C++ libraries out there.

I feel C++11 could use some kind of new approach, like "Lean C++11" which drops all the legacy crap that is holding back adaption for new developers, who now have to go through maybe 15-20 years of legacy coding styles in order to find the modern way of doing things.

But this would break backwards compatibility, so maybe better focus on Rust or something else that is set to do things correctly.

I still like C++, although it is more difficult to write in. Add in a scripting language like Lua to C++ and you have a very performant and nice stack of scriptability and close-to-the-hardware stack that feels super powerful.