66 comments

[ 2.1 ms ] story [ 124 ms ] thread
Operating low-level resources makes it more complicated and because of that, - big amount of programming mistakes made there are critical.
wait, it isn't? I mean, I worked on that, carefully avoiding all the shot_me_in_the_foot features, like non pure virtual stuff, dynamic and static casts etc, but every time I engage in anything as simple as reading boost sources with templates and stuff knitting magic I just get a brain freeze and get back to java
Any language you choose is as complicated as you make it yourself. Some of the cleanest, simplest and most readable code I've seen in my life was written in C, while the most horribly complex, obtuse and over-engineered projects I've seen were written in Java.
-1 for use of "codes"!

(arguably C# is the "top C++" with its managed/unmanaged distinction)

OK, so clearly the idea that "code" is a mass noun rather than a plural is very unpopular. Or I've failed the "don't be negative" rule.
The most favourable thing I ever heard anyone say about C++ is that it is a decent language if you only use some parts of it.
I think it's a true statement though.

Same for JavaScript :)

I support the idea of dividing C++ into two. That way people can start by learning top C++, use it for some years and start to use features which are on bottom C++ after gaining some confidence.
The 'pro' features are heavily used by library designers. In practice, written C++ is indeed, along the lines you mention.
Because it looks like a standardized set of kluges suffering from the kitchen sink sindrome? (compared to well-designed languages)
C++ is the perfect example that shows that you can't build a language incrementally, while maintaining backward compatibility. You have to oversee all the issues, and define the language accordingly.

I'm afraid after a while, Rust will see the same problems, unless they let go of backward compatibility.

That's the reason Scala doesn't guarantee backwards compatibility for major releases. Of course, there is always someone who complaints about it not being enterprise ready.
I think Rust is more like early Java. If you start with a good base, the things you need can be introduced relatively smoothly on top of the existing language.

C++ is the oddity, in that it is trying to become a completely different language. Rust won't have that problem.

I fully agree with the authors concept that C++ is both a high-level and low-level language, and it is important to choose the right 'sub-language' for a given context.

I'd love to have the ability in C++ (and basically all other languages) to turn on/off language and standard library features right in the source code, it would do wonders for the maintainability of projects with many contributors and large code bases in general.

Instead of writing a style guide in the sense of "don't use new/delete, don't use raw pointers or arrays, don't use exceptions, don't use CRT functions, don't use stl containers, etc...", and hope that everyone follows the guide or catch violations in code reviews, the style guide would be part of the source code, and violating it would result in compilation errors.

Like an automatic linter/formatter?
I was thinking more along the line of "#pragma disable(std::vector)", but a post-processing/analysis tool could do the job as well I guess. Would be a nice addition to the LLVM tools family.
IIRC we're about to deploy this so it must already exist :P
Sounds like a great idea for a check-in tool.
I will soon be making a library and will be used on micrcontrollers and PCs. I'd like to use C++ but past experiences suggest that using C and writing a C++ wrapper later will save me frustration with things like code size and manual memory management.

If I could turn off a number of features, C++ would be great. I keep flashing back to blog posts [0][1] written by the ZeroMQ author trying to settle on C being the way to go.

[0] http://250bpm.com/blog:4

[1] http://250bpm.com/blog:8

A few words of advice: don't use C++ on microcontrollers or in kernel code. Explicitness is important for those applications.
One of the first things he says is that constructors and destructors can't be used. Is that true? If so, why?

Exceptions should be able to be turned off in the compiler, but destructors, move semantics, simple template type substitution, and lambdas should be zero overhead in modern C++11/14.

I think a lot of people think about C++ and think inheritance and exceptions, but after having done modern C++11 for two years, those are two of the features I've used the least.

It's not that constructors and destructors can't be used.

What he said IIRC is that you can't manage errors in them without either using exceptions or using trivial constructors/destructors plus a state machine for the remainder of the lifecycle (initialisation etc). As he's mostly into writing libraries not applications, both approaches were, in his opinion, more hassle than they were worth.

Many embedded style guides argue against dynamic memory allocation altogether. So you statically allocate all the variables you will ever need. And in an embedded environment there may not be a loader to run the constructors, or you don't want to run them at bootup until you've configured the DRAM or suchlike.

Edit: the ZeroMQ point is that, if you have a constructor or a destructor, then it must not do anything that can fail because the mechanism for recovery is an exception and clean recovery from exceptions bubbling up through code is quite hard to achieve. This is basically the Go/Rust argument against exceptions and in favour of explicit error return.

Honest question: why wouldn't someone want to use STL containers?
A bit of the no one ever got fired for buying IBM. By using the STL containers you can quickly learn a not great, but not horrible API and have a good chance of it being around down the road, your stuff will still compile, api wont change and it might be available on other platforms.
Honestly, the API doesn't seem that bad when you understand what it's trying to achieve. There are some hairy areas though (dealing with std::bind many years ago comes to my mind, but I didn't understand back then that they were basically trying to shoehorn half of Common Lisp into C++).
Because someone might require different tradeoffs than those that were chosen by the STL's designers, such as in game development.

Which is why EA created the EASTL: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n227...

Do note that some of the issues with STL as pointed out in the link above got improved upon as both implementations and compilers improved.

Once I was handling a big data set for natural language processing. It's big enough it nearly ate all my memory and was somewhat slow if I remember correctly. Then I switched to a C-based toolkit, memory usage dropped significantly. I never knew STL overhead was high until that point. Yeah STL is great, but for big data, maybe not.
They aren't always the right tool for the job. Maps allocate every node separately (c.f. Boost Intrusive). Vectors don't generalize to multiple dimensions efficiently. Lists for a long time had only the doubly linked type. Vendor specific hash tables had O(n) erase by iterator. Strings are not part of the STL strictly speaking, but anyway they have had varying performance and design characteristics on different platforms...e.g. short string optimization.
GNU pissed me off in the latest long-awaited ABI break by making std::string a whopping 32 bytes on 64bit platforms, yet only supporting 16 bytes inline for SSO. Their argument is it takes no more memory because std::string always allocated at least that much anyway, but it bloats structs and classes unnecessarily, and every single other vendor does it better.

I don't think you can blame the C++ standards committee for vendors creating shitty implementations.

At the moment, unless you're exposing an object via a public API, I recommend using boost::string and boost::multi_index for hash tables. In public APIs expose a good old fashioned char*,size_t pair, or copy to a std::string.

We worked on a game that was being released simultaneously on 6 different platforms. STL was out of the question, too much overhead, we wrote our own containers for pretty much every single platform.
Because they're well designed, good enough 90% of the time, safer than writing your own, and easier than finding and integrating another library.
I use STL now, but in the past I've seen several reason not to.

Compiler support hasn't always been there, especially on embedded systems with old or poorly supported compilers.

Strict control over memory allocation hasn't always been possible with STL, and it's still not very convenient if/when you need your own allocator, e.g., embedded systems, console games.

And this isn't true any more, but I still remember what the error messages used to look like more than 15 years ago. Sometimes a single error exceeded the maximum output length for error messages in whatever compiler I was using, probably Microsoft's, and you couldn't actually see what the problem was. That left me with impressions of STL that took a long time to recover from.

»General relativity has a reputation for being very difficult. I think the reason is that it is very difficult.«

Leonard Susskind

Is your next post 'Why people think keeping a website up is complicated?'
I never found C++ complicated but I suppose it's because this was the first programming language I really learned. When you're learning your first language, you don't have any frame of reference yet to compare it to. You either grok it or don't. And then it becomes your baseline for programming, you compare next things you learn to that first language.
C++ is not complicated, it a language that offers a range of features and paradigms, and doesn't make you pay for what you don't use, unlike some languages. However, modern "developers" are often impatient, have a frame of reference that everything is ruby or js, not to worry about any resources (they are infinite, right?) and think all their problems can be solved via gem or npm install. The modern software stack has therefore become a bigger pile of more diseased turtles, all the way down.
It's hard for me to disagree with that given what often passes for "teaching people to code". I don't find being introduced to a high-level web framework as a good way to begin. You end up typing magic into a file within a big folder structure you have no idea about why it's there, and installing yet another library for every trivial task.

One think I loved when learning C++ (and which makes me feel it's not complicated) is that pretty much everything felt like a logical decision if you understood you're just one step above metal. Now I know I was mistaken back then in some ways (by e.g. believing that C memory model is exactly how things are done in hardware). I now believe that every language will feel logical and reasonable if you end up learning about the reasons why it looks like it does and its relationship with what your hardware does.

It sure is complicated, and I say that as a full time c++ dev who sees it in a generally favourable light.

There is a huge amount of knowledge that you need to pick up over the years before you can consider yourself even an advanced c++ programmer let alone an expert.

In my experience it's way more complex than c, JavaScript, Python and any Lisp. However, you can use it in a c-like fashion and avoid some of the complexity but if you want to work with anyone else's code then you have little choice but to learn that complexity.

It is complicated compared to many other languages - that's why I wrote that I didn't find it this way - I didn't know any other language then, so C++ level of complication became my baseline (which made me find most other languages seem very simple).
C++ is not complicated

We need some frame of reference or objective standard, but I'd say: that is wrong.

Anything can seem complicated, or like magic, until you take a little time to learn about it. I am always wary of people claiming other languages are not complicated, or easy, because then I realise they probably have not really learnt that other language either, and are making superficial comparisons based on their lack of knowledge and experience.
The problem with C++ is that the more time you take to learn it, the deeper the rabbit hole goes.

For most languages I have the feeling I'm getting more proficient as I use them. Not so much with C++, especially if you get exposed to other people's code.

(comment deleted)
Perhaps a bit off-topic but serious question. I don't understand whenever someone says language A is next to bare metal? What does a language have anything to do with bare metal or performance? Isn't it the compiler/interpreter that performance is about?
It's about how much the language intrinsically prevents the compiler from optimising the output. Think Javascript versus asm.js, same language, one is just a subset of the other, completely different performance outcomes for the JIT compiler.
Languages like C and C++ compile down directly to machine code, and the resulting machine code is run from then on the bare metal without any further translation.

Interpreted languages such as Python or Ruby (or languages that run on a VM, like Java) go through an interpretation step _every time_ they are run that translates them down to machine language.

This gives compiled languages an inherent advantage in terms of runtime performance; programs written in these languages don't have the overhead of translating to machine code at runtime. This is typically why people advocate "next to bare metal" as having better performance.

That said, it's a about the implementation not the language itself. The phrase is technically incorrect, right? One could write a compiler that compiles Python or Ruby down to machine language without the interpretation overhead, and not necessarily faster or slower than their original interpreters, or other C/C++ compilers.
That's technically true, but I think it has more to do with the programming model. 

In C and (sort of) C++ you can deal with actual bytes in actual memory locations. You can find the exact memory address of a data structure, and you can read or write directly to that location.

You can even prod the compiler to suggest that it uses real hardware registers for variables.

You can also control how memory is allocated and released.

In most languages an array is just an array. You usually don't care where it is in memory.

In functional languages you concentrate more on designing symbolic operations, and the fact that there's real memory under there somewhere is almost irrelevant.

But C/C++ are bare-metal-ish. In assembler you work directly with memory, but you can control program flow. You can jump/branch to any address in memory. Sometimes you can even overwrite your own code.

C/C++ won't let you do that.

As a former assembler guy, I find that C++ is the worst of both worlds. You get the cognitive overhead of dealing with memory management and pointer arithmetic and iterators, but the options for not working with them when you don't want to are limited - so it's hard to concentrate on the functional level, and you do a lot of the work the compiler/interpreter would usually do, but without the "do whatever you want" freedom of assembler.

If you pry open your computer and look through a microscope, you won't see any closures or lambdas. You won't see any private class members, much less any kind of inheritance or dynamic types. You won't see any microchips dedicated to try/catch/throw, you certainly won't see an 'exec' circuit. You won't see any kind of DOM, shadow or not.
I don't think it has anything to do the relationship between the language and its (compiler/interpreter) performance. Besides, the subset of a large number or programming language could be considered bare metal, right? If so, why mentioning bare metal at all?
Most things you do in a language like C, have direct counterparts in the physical machine. If you get into stuff like game hacking, you can literally "see" these things through whatever RAM-hacking tool you're using.

Dereference a pointer? That translates to a tiny fragment of machine code for "dereference pointer".

Create a lambda? That translates to a big blob of machine code for "set up this bunch of paperwork that will be used to painstakingly emulate a lambda".

And what does it have anything to do with C++ compared to any other language X? The bare-metal characteristics could be created as a subset of any non-safe non-garbage-collected language.
You're right. I think someone else already pointed out asm.js as a good example.

Of course, it won't happen magically: someone has to go to the effort of defining the subset and building the compiler for it.

You can't expect the general-purpose compiler to automatically be as optimal as possible just because a program happens to use the subset. For example, the program might be being compiled into something like a java .class file meant for importing to a less conservative calling program. This would be incompatible with putting those bare metal optimizations in the .class file.

If the language defers explicitness until runtime then there's nothing a compiler or interpreter can do to get rid of the overhead.

With things like a JIT it can see it at runtime, but that's still overhead to handle the detection and the bail-out situations.

I agree on the overhead. There are information available only at run-time that could be (and actually has been, in case of interpreter like PicoLisp) used to have better optimization compared to compiled code. It isn't technically faster or slower.

Edited: Correct my bad grammar.

"Error establishing a database connection"

But I would say it's because others are easy.

Yes others are hell lot easier.

"Error establishing a database connection"

But I would say it's because others are easy.

Yes others are hell lot easier.

I think having to to divide the language into two semantically exclusive sublanguages answers the question of the author. (Though the title here is not his title...) The other answer (which there was an article about a few months ago which was posted here) is "Because having exceptions is really complicated when certain object actions can't throw exceptions."
Isn't that what happens in the arduino, where users use top-c++ ? and it works pretty well for them, in a very harsh, constrained environment.
http://tehsausage.com/ptypes/doc/inet.examples.html

vs

http://www.boost.org/doc/libs/1_35_0/doc/html/boost_asio/tut...

I know a lot of people would criticize the practices/styles used in ptypes - but I've yet to see another C++ library that is as easy to use, easy to read, AND most importantly cross platform. Hell even raw sockets in C is easier to use and understand than boost [1].

This is one of my favorite comments on reddit [2].

[1] http://www.thegeekstuff.com/2011/12/c-socket-programming/

[2] http://www.reddit.com/r/programming/comments/197dn1/introduc...

I am a C艹 beginner from Python and C. I feel that the handling of trade-offs between performance and safety/explicitly is passed to programmers and not the language itself, which made it difficult for beginners to capture what is the best practice. Choices may be good for experienced programmers, but they are not very friendly for beginners.