Popular Myths about C++, Part 3
isocpp.org
isocpp.org
> “C++ is an Object-Oriented Language”
> “For reliable software, you need Garbage Collection”
> “For efficiency, you must write low-level code”
> “C++ is for large, complicated, programs only”
Well, 2.5/5 of those aren't myths. You certainly don't need to write low-level code for efficiency, C++ does a rather poor job of acting like an OO language, and you don't need Garbage Collection, you just need to not manage memory manually, for which solutions other than GCs exist.
You don't have to learn all of C to write C++, but unfortunately you have to learn C to understand other people's C++, because other people will not restrict themselves to the subset of C++ you consider respectable. That's true both for the C bits of C++ and for the obscenely complex corners of C++.
And C++ isn't just for large, complicated programs; it's for small, complicated programs too.
hahahahahahaha!!!!!!!!!!!!!!!!!!! -- I was thinking that, but hadn't put it into those exact words yet.
I was thinking something like "C++ is definitely for complicated programs" -- not that they necessarily need to be complicated, but that C++ often unnecessarily complicates them.
I really wanted to like the STL a long time ago, but I gave up eventually. Happily my frustration with C++ led me to investigate other programming languages (not that it was the only one I had used), and I write precious little in it lately -- mostly just to modify code others have written in it.
This is an important difference with most subreddits (some, like /r/AskHistorian have a similar ambiance); it avoids ending up with long, heated and shallow conversations.
I didn't just leave it at the onomatopoeia -- I made a very reasonable comment afterwards.
I am not sure which language are you comparing it to but there is definitely a subset of C++ that is easy to use, very readable and type safe.
My only problem with C++ is somebody else code, because there is also a terrible subset of C++ where things can turn very hairy. But same can be said about C, and actually C sometimes encourage you to be "clever".
However, there are multiple other languages that I would rather program in -- although there are still places where I would chose to use C or C++.
I was mostly disappointed that when I tried to use many of the features of C++ that were beyond an intermediate level, the real warts of the language made it not worth the hassle.
I suspect some of that has improved in the latest version of the language spec (and some in the version prior), but I haven't seen anything so far that has excited me enough to get back into it much.
For example, the following generates about 2KB of instructions (and will for basically every new type you want to sort):
#include <algorithm>
struct SomeStruct { int X; };
void foo(SomeStruct *SS, int NSS) { std::sort(SS, SS + NSS, [](SomeStruct LHS, SomeStruct RHS) { return LHS.X > RHS.X; }); }
A qsort equivalent will only emit code for the comparator which is just a handful of instructions.
C++ templates may be type safe and all, but at the end of the day they spew duplicated code just as much as those header-only macro-based C containers and algorithms; really more because it's less painful to write templates (vs. macros) and so you do it more, and there is more stuff in the templates. So even though in general the specialized generated code might be faster in most cases (as Bjarne likes to tout), the overall hit on your code size (and i-cache) can be dreadful. Currently, avoiding this issue in C++ just requires diligence on the part of the coder (some optimizations like LLVM's mergefunc can help, but in general it is a pretty hard problem and compilers are not Sufficiently Smart (TM) yet).
LLVM + libclang together are already 46MB of code, and they're libraries designed to be statically linked. Sure, they aren't going to fill your drive, but they will take a comparative while to load from disk (especially as part of another application - doesn't matter much on the command line), and it's that much harder to justify including them in an otherwise small downloaded package.
Edit: it was DICE, see http://www.slideshare.net/DICEStudio/executable-bloat-how-it... - skip to page 14.
This is an interesting optimization, but it's not suitable for a beginner-to-intermediate C++ audience, which is who Stroupstrup is addressing. The sensible default is to use std::sort.
If someone can (and it looks like you have) measure a benefit in doing something special, then she should have at it. If an entire project, again with measurements, can prove that std::sort shouldn't be its default sort algorithm, that's fine too.
I can't speak with authority to C#, but C++ is a massively larger core language than Java with far more complicated semantics.
C++11 and C++17 might be quite a pleasure to use when a small team controls all the code, unfortunately most of the real world applications are done in pre-C++98 style.
And then, you still need to learn about each libraries use which version of the standard.
This is why there are so many fundamental types like string duplicated everywhere. We had to rely on third party libraries like Tools.h++ for consistency across compilers and OSs, before the majority reached C++98 compliance.
There are caveats: the compiler might not choose to inline unless you force it to, and if you do that then you'll end up with duplicate code in the case of multiple calls with the same comparison function, while C++ can automagically merge duplicates (although you probably want to write a wrapper function anyway, and C++ will still waste compile time generating the duplicates if the calls are in different source files). Also, if the sorting function calls a secondary function in multiple textual locations, and that function is significant enough that inlining it would produce wasteful code, the pure inlining-based approach will be insufficient (but I don't think most sorting algorithms do this).
In other words, C++ makes it easier to do this sort of thing. No surprise! It certainly makes it prettier. But when it comes to performance, in practice the above would likely not be a big deal for qsort, so the difference between the two functions is really more a matter of convention regarding the implementation location. Benchmarking the two and explaining only that type safety "makes for excellent inlining and good optimizations" is simply misleading.
which i found shocking, but there it was. my perception was different from the reality.
Surely we care about build speed, but there is no need to care about such micro optimizations as qsort vs std::sort. Most of the speedup is in correctly separating translation units and not including unnecessary header files (sometimes forward declaration is enough for example...).
With that said, when there are some tradeoffs then optimizing build speed is among one of the last things we care about.
Yes. Which is why C++ needs modules. It's a big problem when people have to alter their designs to work around their tools (compilers, in this case).
My question was more focused in having to work around the compiler by doing micro-optimizations, or avoiding some features that "may be heavy", just because one project will take 65535ms instead of 65000ms to do a minimal rebuild.
But at the end of the day, it really depends on the dimensions of the project. In a huge project an improvement from 8 hours to 7.5 hours is greatly appreciated.
The cost of template instantiations by itself is not too significant, and they ought to be cacheable in the future C++ module system, along with the header file parsing that's the biggest factor making C++ take longer to compile than, say, C. But with today's compilers, it all adds up.
Well, here you go: https://gist.github.com/ridiculousfish/bb511993deba1d148317
qsort: 674 ms
std::sort: 1104 ms
qsort only requires one invocation of the comparator to determine the order, while std::sort often requires two. So qsort ought to be faster when comparisons are expensive. qsort: 6727 ms
std::sort: 6718 ms
(CPU is Core i7-950)This may be a pathological case for either implementation, since the array is already sorted. Still the point about std::sort requiring up to twice as many comparisons is valid.
qsort: 4415 ms std::sort: 4413 ms
Some comments:
1.) std::sort doesn't require twice as many comparisons
2.) You not only have a vector with equal items, you have a vector of the same item repeated. That removes all data cache issues which I think is generally unrealistic and unfair.
3.) An already sorted vector is not only pathological, it's something that you usually need to optimize for (probably both qsort and std::sort are bad choices)
Oh come on.
qsort: 6112 ms
std::sort: 4925 ms
Compiled on x86_64 with gcc 4.7.2 at -O3. I'm sure there are many possible reasons for the difference in performance.Edit: Actually quicksort only needs a stable boolean comparator (e.g., < or >) to determine order. So the number of invocations to the comparator is the same for both qsort and std::sort. Source: http://en.wikipedia.org/wiki/Quicksort
I would amend my top-level comment but I don't seem able to.
sort(v.begin(),v.end(),[](const auto x, const auto y) { return *x > *y; });
instead of your line 39: sort(v.begin(),v.end(),[](const string *x, const string *y) { return *x > *y; });
Some results:• g++ 4.9.2 with O3 qsort 545ms, sort 7289ms
• clang with O3 and libc++ qsort 551ms, sort 844ms
I've used:
clang++ -std=c++1y -stdlib=libc++ -O3 test.cpp
and g++-4.9.2 -std=c++14 -O3 test.cppI've updated my tests and qsort seems to be faster than sort, for this particular test case.
qsort: 5818 ms
std::sort: 4948 ms
Ubuntu 12.04 x86-64; g++ and clang++ give the same results.EDIT: with clang and libc++, same compilation line otherwise:
qsort: 5822 ms
std::sort: 571 ms qsort: 10466 ms
std::sort: 5137 ms[1] http://locklessinc.com/articles/vectorize/ [2] http://stackoverflow.com/questions/1965487/does-the-restrict...
I'm not really sure about the rest of the myths. I'm a little confused about how "To understand C++, you must first learn C” is a myth since C++ is a superset of C so you kind of have to learn C.
[1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n227...
Although true, I feel this argument is rather weak: it's true, that when teaching I wouldn't want to start with pointers and malloc's from the get go, but it does not mean C++ is the only alternative.
If you're teaching systems programming, don't hide pointers. In this case, knowing the addition operator is useful iff they understand the underlying operations.... chances are, if they're learning C++, they don't.
It's difficult to find a place for C++ in my little projects, given that I can use C for low level stuff and Python or Lua for high level stuff.
But got to say, my experiences with learning C++11 has changed how I view C++, it's much more robust and nice environment than what I thought, the new C++11 and C++14 really bring some nice things to the table.
The myth in "To understand C++, you must first learn C" is not that C and C++ are unrelated. The myth is that learning C helps you understand C++. The reality is that telling people to learn C first is an excellent way of getting them to write really bad C++ when they switch over to C++11.
Is that something new in C++14, coulnd't immediately find it on the net? Or is it just a version he wrote himself? The latter makes sense for pretty much all algorithms in <algorithm> which you'd use often on a container, to the point you'd start wondering why the standard doesn't provide them built-in.
int greater(const void* p, const void* q)
{
return *(double *)p - *(double *)q;
}
would work just as well.EDIT: DON'T USE THIS, WONT ALWAYS WORK
vector<double> v = {0, nan(""), 1};
sort(v.begin(), v.end(), [](double x, double y) { return x>y; });
In my test this leaves the vector unchanged, which is definitely not in decreasing order.I'll just say I'm not a fan of C++ and would rather write my own language similar to the source-to-source compiler idea of HaXe ( http://haxe.org/ ).
It's the catbirds in the gallery that don't actually have to write the kind of apps that require a language like C++ that "bash" it.
The kernel and git are in C
And if you've been programming C for 20 years or more, writing git with C feels like a natural solution.
It's not always about writing stuff with the most high definition solution, it's more about expressing ideas with the tools you know also.
Quintessential Linus, but I wouldn't call this an "evaluation"... :)
As a side note: I think we as a community should promote the catchphrase "You've Been Torvalds'd".
But since lava layering is caused by cultural and architectural issues I cannot claim that the system would be in any better shape just if some other language had been used.
Let's do something simple, a function that returns a reference to an array of a known size.
Some of C alternatives would be:
int (*foo())[2] {
}
or maybe if you have the length somewhere else: int** foo ()
{
}
or you could try to implement or use an existing implementation of a dynamic array (nothing in the standard as far as I know)vs.
std::vector<int>& foo() {
}Yes. C is very small and simple. You can learn all of C in a very short time. C++ is the most complex programming language in existence. It is unlikely that there is any person in the world who actually knows it all, including the creators.
>or you could try to implement or use an existing implementation of a dynamic array
Imagine that. You could use libraries that implement things you want. What a concept.
I think I didn't explain myself, but something that basic in these days should be on the standard library in my opinion.
>"Yes. C is very small and simple. You can learn all of C in a very short time."
I don't think C is simple at all. Its syntax can be really cumbersome at times (see my first example). Also it is very annoying to debug, and C code is very prone to contain memory corruption bugs and leaks.
C has great advantages but being simple is not one of them.
Ok well you hop in your delorian and go back to 1970 and let them know. In the mean time, how does that in any way make C not capable for the same tasks as C++?
>I don't think C is simple at all
Then you don't know C. The entire point of C is that it is simple.
>Its syntax can be really cumbersome at times
That has nothing to do with simplicity, and C++ has far more complex syntax.
>Also it is very annoying to debug
C is very simple and straight forward to debug. C++ is much more difficult to debug. Have you ever used either language?
>and C code is very prone to contain memory corruption bugs and leaks.
Because it is so simple.
>C has great advantages but being simple is not one of them.
Well your opinion is in the vast minority, and does not seem to have any basis in reality. The C spec is a tiny fraction of the size of the C++ spec.
Well they could have added in C99 or more recently in C11. What's wrong about updating a language?
> In the mean time, how does that in any way make C not capable for the same tasks as C++?
I would rather prefer not reinventing the wheel and a language that actually ship with it.
> Then you don't know C. The entire point of C is that it is simple.
I know C fairly well to recognize it quirks (just like all languages have). I think your definition of simple is very different of mine. Scheme is simple, InteractiveC is simple, C it is not.
> That has nothing to do with simplicity, and C++ has far more complex syntax.
cumbersome(adj): difficult because of extent or complexity
simple(adj): 1.easily understood or done; presenting no difficulty. antonyms: complex
How come something cumbersome has nothing to do with simplicity?
Also I am not saying that C++ is simple. But it has a subset that it is well defined, type safe and easy to understand.
> C is very simple and straight forward to debug. C++ is much more difficult to debug. Have you ever used either language?
Yes, I have used both in my formal job, and I can avoid memory leaks and memory corruption easily on C++. Not the case on C, specially when working in medium size teams where always people forget what they should cast a void* into and why they should not.
>>and C code is very prone to contain memory corruption bugs and leaks.
>Because it is so simple.
Seriously? It is a feature now? Well Scheme is a good example of language that is order of magnitudes simpler than C and it is not prone to memory leaks nor memory corruptions
>"Well your opinion is in the vast minority, and does not seem to have any basis in reality. The C spec is a tiny fraction of the size of the C++ spec."
If by simple you mean simpler than C++, yeah. You could say the same of Perl. Does is it make Perl a simple language?
Nothing, they do update the language. But fundamentally changing the language to be completely different is not the same as adding some small thing. C is simple on purpose. Adding complexity is not just an update, it is making it no longer suitable for its intended goal. So they choose not to.
>I would rather prefer not reinventing the wheel and a language that actually ship with it.
You don't have to reinvent the wheel, use a library like you already said.
>I think your definition of simple is very different of mine
Clearly. But mine is the same as 90% of the people who have commented on the subject. People overwhelmingly describe C as simple.
>Scheme is simple
Yes it is. As is C.
>How come something cumbersome has nothing to do with simplicity?
You just quoted how. Are you joking?
>Also I am not saying that C++ is simple
But you are arguing that C is complex and thus not appropriate, while C++ is appropriate. You can't have it both ways.
>Yes, I have used both in my formal job, and I can avoid memory leaks and memory corruption easily on C++
Which has what to do with debugging? And why are you incapable of avoiding those problems easily with C when everyone else does it just fine?
>Not the case on C, specially when working in medium size teams where always people forget what they should cast a void* into and why they should not.
Yes, clearly there's no way groups of people could work together on large complex software in C. I'll go tell linux, apache, X, all 4 BSDs, nginx, postgresql, postfix, etc, etc, etc that they don't exist. I'm sure they'll be glad to know.
>Well Scheme is a good example of language that is order of magnitudes simpler than C and it is not prone to memory leaks nor memory corruptions
Scheme is not even one order of magnitude simpler than C. Go read the specs. And scheme is not prone to memory leaks and "corruption" because it is higher level. This also makes it much slower. Even more importantly, it makes it a ridiculous comparison.
>If by simple you mean simpler than C++, yeah.
You are the one advocating C++ over C while claiming C is too complex. What are you blaming me for?
Was it? Most console games are written in C++ in that period of time. A very popular desktop office suite is built on C++. The most popular design and photograph edition tool for Windows is written using C++.
So you are suggesting that all those guys who picked C++ for those popular piece of software are a sort of lucky morons?
It is a strong and risky assertion don't you think?
That is C. Lots of C compilers supported // comments, like watcom which they used. Notice the file extension says it is C. Notice it uses absolutely no C++ features at all.
http://en.wikipedia.org/wiki/RollerCoaster_Tycoon Still using ASM in 1999. Go look at quake 3 which was when id started into C++. Notice how it is barely C++. It seems odd to "suspect I am mistaken" rather than look at the evidence which lines up exactly with what I said.
I don't think RollerCoaster Tycoon is a good piece of evidence because it's famous largely for being written in assembly at a time when most games had already abandoned it.
(Sadly, I don't think it would be odd at all to ignore the evidence, but I aspire to better than that.)
There are still a lot of problem areas where GC is unacceptable, or you need precise control over memory, or access to things like Cuda, along with the high order programming constructs you get in C++.
Maybe Rust will take over some day ...
(It's entirely possible that all six of these languages are terrible, but that would be six separate claims.)