Cee Plus Plus Slower Than Cee

Often an argument is made that C++ is inherently and unavoidably slower than C. What is your experience?

In a narrow, technical, sense, it's obvious that C++ is not necessarily slower than C; while C is not a true subset of C++, it's close enough so that one could write standard C++ that was pretty much indistinguishable from the equivalent C program. The issue is whether using constructs only found in C++ necessarily makes programs slower. This is best addressed by looking at the cost/benefit of particular C++ constructs.

And so on.

But one can write blazingly fast programs in C++, as long as one's aware of the potential pitfalls. And, yes, you can use exception handling too, along with everything else.
As far as I know (from TheCeePlusPlusProgrammingLanguage IIRCs) C++ was designed to be AsFastAsCee if you didn't use any C++ features. Particularly the ExceptionHandling did bother implementors quite a bit, because 'simply' adding a heap record for try-catch blocks wouldn't do under such a requirement. -- .gz
Discussion on inlining moved to CeePlusPlusInlining.

'''...and the following moved back, since it has nothing to do with inlining:

From CeeLanguage:

CeePlusPlus was one effort to add ObjectOriented capabilities, and it adds an extra expense to every single method (function) call made, even in pretty trivial cases.

Calls to static class methods, non-virtual class methods, and free functions (functions not part of a class, just like in plain old C) have exactly the same semantics as a C function call. If a function is implemented in C++, there may be additional stuff in the function prologue/epilogue to deal with exception handling; functions implemented in C don't incur this expense. If no exceptions are thrown, we're talking a few instructions. Calls to virtual functions incur an additional expense, as a) you need to look up the actual function to call (and adjust the this pointer) for such calls; and b) virtual functions prevent inlining in many cases--unless the compiler can prove which version of a function will be called. The overhead of a) above is generally a few instructions.

In complex cases it can cause a function call to consume thousands of machine instructions before it even gets to the function's body.

Under what conditions? Even with multiple inheritance and exceptions--the number of instructions needed to resolve any C++ function call is bounded--and several orders of magnitude lower than "thousands". Now, if a function call causes a page fault and you count the instructions that the OS uses to service the page fault, that's another matter--but that affects C just as much as C++.

It is infamous that people are often astonished to single step through their code, and quite literally discover that thousands of machine instructions occur before they reach the method body they thought they were calling directly. If you think about it for a second, you'll recall that this does happen.

[But we don't remember that. I spent several years stepping through C++ code at the instruction level on VMS and I never saw it take thousands of instructions. Perhaps there's some particularly bad C++ implementation out there, but I haven't seen it.]

I'm talking about the experience where people are astonished at the vast numbers of constructors, often including many many trivial constructors, but also including nontrivial ones that call nontrivial code, that get called that they didn't realize would get called. This used to be even worse than it is today, but it happens even with good C++ implementations, because the language is just doing what it was told to do, but regardless, it happens. In C, there are no such hidden costs. A call is just a call in C.

{Right. But that's a vastly different thing than the statement that was being critiqued above, which is completely wrong. Dynamically-dispatched virtual function calls add a small amount of overhead. If you use the OO features sparingly, that's all the cost you pay -- and it's usually offset by the savings in conditionals. Unwise use of some features -- e.g. passing complex objects by value, which would cause the constructor overhead you mention -- can lead to a lot of overhead. But the answer to that is "don't do it". If people are astonished by such things, it's because they didn't learn their tools well enough. If such features are used appropriately, they add overhead which offsets the savings you get from not writing a lot of code that does similar, necessary things -- like allocating and copying data. -- DanMuller}

It is not vastly different, and the original was not completely wrong, and you are not disagreeing, you're in violent agreement. :-)

You said "small amount of overhead...sparingly, that's all the cost you pay." The original said "adds an extra expense...In complex cases it can cause a function call to consume thousands of machine instructions ". Those two statements are in agreement.

At most the argument is about emphasis, like in the old joke, "we've already established what you are, now we're just haggling over price." ;-)

-- DougMerritt

Er, OK, I might have slightly overstated the case. I retract "vastly". But your selection of quotations skip over the true error: ".. it adds an extra expense to every single method (function) call made.." [emphasis mine] is actually wrong. Typical C++ -- notice I'm not saying 'well-written' C++ -- has a lot more non-virtual member functions than virtual ones. And those don't pay any inherent extra expense -- non, nada, zippo. If you pass complex objects by value, you'll add overhead -- but again, in my experience, this is not a terribly common to mistake among minimally educated C++ developers. So -- yes, completely wrong because it was stated as an absolute, and even if you replace "every single" with "most", still wrong, according to my experience. The discussion also ignores the fact that at least some of that overhead is replacing things that you would have had to write out explicitly if C++ didn't allow for a greater economy of expression. (I can't believe I just wrote that -- C++ is still way too verbose.) Yeah, it's true that a lot happens implicitly which would be explicit in C, so if you're not familiar with the characteristics of data structures that you're using, you can get surprised. But with reasonable care and only a few good coding guidelines, this can be, and in my experience usually is, avoided. -- DanMuller

Good style is virtual, which has overhead, typical style is non-virtual, but that still invokes constructors, which is overhead. You can assume constructors are optimized into inline code, but are they always? No. Are they by default? No. Does C++ style (good or bad) cause very frequent use of constructors, e.g. for member initialization? Of course. Even if optimized into inline assignments rather than function calls, is there a resulting increase in the amount of code compared with C? Yes. In "complex cases", as above, can this amount to thousands of machine instructions before the method's main body is reached? Absolutely; I've seen it happen.

I've worked on the internals of multiple C++ compilers professionally, in addition to using C++ in various non-compiler projects. I've seen a huge amount of different kinds of code. I'm not making this up. But notice, I'm not making any blanket statements like "...and therefore C++ is always slower than C", which would be easy to think I am implying, but I'm not claiming that.

I'm merely claiming that in C, a call is just a call, but that more often than not, that's not the case in C++. This may or may not matter in individual instances.

BTW someone above claimed that "inline" would always inline. I'm a few years out of date, but that used to be absolutely false, it was advisory only, and compilers would typically refuse to inline functions larger than some threshold in size, nor was there any standard way to force the issue, nor to get a warning if the compiler did not inline. Did this change in a newer version of the ever-changing C++ standard? -- DougMerritt

I disagree only with this: "Good style is virtual." Where I've worked, it's: "Good style is using the language features you need."
There is another case where the C++ form is slower (or takes more data space...) than the C form: pointer to function Vs. pointer to member function.

Apples to oranges. C-style FunctionPointers exist in C++, and take the same amount of space. PointerToMember?s are an altogether different beast; you use them in a different context. In many years of C++ programming, I seldom find a need to use PointerToMember?s.
I rarely work at or near the UI level; much of the software I've worked on is supporting middle-layer code and lower. In such code, where performance often can become an issue, I've always had this habit. The result is that virtual functions are easily the exception rather than the rule. Also, I and those I've worked with make heavy use of const reference parameters. If I suspect that an object is larger than a pointer, then I would not usually pass it by value unless there was an advantage to having a mutable copy on the stack at the receiving end. This means that such objects are almost always being passed in exactly the same way that you'd pass a struct in a C program. Given these habits, I don't expect most function calls to incur more overhead than a C call. Am I missing something? To answer the question at the top of page carefully and completely ("Often an argument is made that C++ is inherently and unavoidably slower than C. What is your experience?"), I've never done a strict performance comparison between similar programs written in C versus C++. However, I've spent quite a bit of time investigating performance deficiencies in C++ code. Rarely, if ever, was a problem due to overhead inherent to using C++. That's not to say that there wasn't such overhead, but it doesn't make it onto the radar screen as an issue. Occasionally I work on code with very compute- or data-intensive algorithms. In such cases, where I know (or find out very quickly) that performance is an issue, I will sometimes end up writing in a style that's much closer to plain C. In such cases, you do have to stay aware of what the various C++ features actually do (or can do). But I'm having trouble thinking of any performance overhead in C++ that is unavoidable. Perhaps common standard library routines suffer from some inherent overhead due to support for language features that you might or might not use? (Cf. the following poster's comment on exceptions.) I don't know. -- DanMuller For an apples-to-apples comparison of C and C++, the best test is to compile C code with the C++ compiler (assuming, of course, the C code is valid C++; C code that isn't valid C++ usually contains a C++ keyword as an identifier, such as "int class;", or else contains some sloppy construct that C tolerates but C++ doesn't). If you see any significant performance difference, you should upgrade your compiler/toolchain. (Also consider repeating the experiment with exceptions disabled, if the compiler allows that). (Agreed! -- DanM)

Agreed. And actually, exceptions can in fact make a difference. It sometimes makes a performance difference to make sure that the compiler knows where exceptions are not thrown. The compiler's life is a hard one; pity it. -- Doug

EditText of this page (last edited July 26, 2005) or FindPage with title or text search