Bjarne Stroustrup Discusses C++
electronicdesign.com
electronicdesign.com
The real novelty here is the return statement: Note that
I return a potentially huge vector by value. In C++98,
that would typically cause the copy of all elements of
res, potentially many thousands of elements. That would
be a serious performance bug. In C++11, vector has a
“move constructor,” so that rather than copying elements,
the representation of res (merely three pointers) is
“stolen” for use in the caller and an empty vector is left
behind. After all, we are just about to return from
find_all() and won’t be able to use res again. Thus,
returning a vector by value costs at most six word
assignments independently of the number of elements.
Move constructors is a simple facility available to every
programmer and used by all standard-library containers
implemented as handles. This allows us to return large
objects from a function without messing around with
memory management (explicitly) using pointers and
free store.
Are most C++ programmers excited by this? Is the idea that people should start writing code depending on this behind the scenes behaviour, or that we now have a way to speed up poorly written code? It feels like an awful lot of effort to avoid returning a pointer. And if I were actually worried about the performance, I wouldn't feel comfortable just hoping it happened. Is there any confirmation by the compiler that it handled this in the way the programmer wanted?"Just use a GC" is a viable answer to this in many circumstances, but probably not all.
Imagine you return a reference-counted pointer from a function. Then every call to this function is a lock/unlock and CPU cache synchronization. And if the pointed object is shared between threads (even for read-only access) this might lead to lot of contended locks/unlocks, which is extremely costly.
If you have a std::shared_ptr<X>, then most of the time you will be passing around "X &" or "std::shared_ptr<X> &" and no copies will happen.
Do you have an example of why a function would be returning a std::shared_ptr<X> by value that wasn't a move?
As of using naked references, you're right, but if you can use naked references, why ever use shared_ptr? Naked references are fine when you know the lifetime of the object.
Don't get me wrong - shared pointers are useful in many scenarios, but they are not a general replacement for GC.
shared_ptr took 17% of time. This is far beyond what GC takes even in a very memory heavy Java application (typically GC stays below 1% overhead).
I'm not saying you shouldn't use shared_ptr at all, but only: be careful.
Therefore a relatively simple operation like pointer assignment can be one cycle when using GC and a hundred to several thousands cycles when using refcounting. Sometimes you can ignore this overhead, sometimes not - depends on how often you do that.
http://software.intel.com/en-us/articles/choosing-between-sy...
The problrm with returning a pointer is now someone has to worry about when the memory that pointer refers to gets ckeaned up. In my current 50,000 line c++ project, there are exactly 3 places where I call new or malloc, and then have to manually worry about cleaning up the result.
It behove users to learn about move semantics before using them (or rather before assuming that they are implicitly using them.) The topic is unfortunately complicated.
Isn't this already the case with some (all?) compilers in pre-C++11?
http://www.parashift.com/c++-faq/return-by-value-optimizatio...
It is passed as a hidden argument to the function, assigning the return value to that argument passed in. Prior to the NVRO, the object was constructed once, a temporary was constructed and then copy constructed to give the result. You can test out the NVRO yourself by putting a printf in an object's constructor, and have the object returned from a function on to an object of the same type.
Stan Lipmann's Inside the C++ Object Model explained it best for me. NVRO applies to the vector object.
The difference here is that Stroustrup is talking about the elements of the vector, not the vector itself, and how the move semantics remove the need for constructing/copy constructing them.
The reason it's notable in C++ is because the code that would normally be called in the constructor is not called as many times as the person writing the code might expect.
In C++ structs can have constructors, but usually have an empty default constructor supplied by the compiler, this is more of an issue when structs/classes have user supplied constructors.
Here's an article giving more specifics of the history of NVRO from Stan Lipmann. Interestingly, NVRO was not added to Visual C++ til 2003, and Lipmann prefers NVRO off by default. I think I recall an NVRO flag in that compiler. NVRO was available in cfront and Zortech compilers in the early nineties. [1]
[1] http://blogs.msdn.com/b/slippman/archive/2004/02/03/66739.as...
The hardware calling convention does dictate certainly what code the compiler can put out.
If the compiler does not support NVRO and emits code that causes multiple copy/constructions it doesn't matter if the hardware supports more efficient behaviour.
I edited my earlier comment with your correction, thanks.
What C++11 provides is a new kind of type that says "it is safe to steal the guts of this value". You can use this to overload a copy constructor or assignment operator to do "moves" instead of "copies". Because it is baked into the type system, it is guaranteed to happen when you expect it. While eliding a copy essentially has 0 cost, and the compiler will still prefer this over a move, moving a vector can have a very small cost (copying a few pointers), but it is still O(1) instead of O(n).
We already trust the compiler to do a lot more tricky optimisations (loop unrolling, inlining, dead branch elimination...) so it doesn't really trouble me.
The time when mortals could more or less 'see' what the memory usage and execution time of a C++ code fragment are is well beyond us.
> C isn’t simpler for C-style programming than C++ is [...]
Is Stroustrup really arguing that C is not simpler than C++? How can it not be simpler? C++ is essentially C with a ton of features added on top.
(FWIW, I don't fully agree with even that statement. C++ makes using e.g. enums with bitmasks much harder than C.)
[1] http://www.johndcook.com/blog/2011/11/11/simple-versus-easy/
"No. C isn’t simpler for C-style programming than C++ is, nor “closer to the hardware,” nor indeed more efficient. I have yet to see a program that can be written better in C than in C++. I don’t believe such a program could exist. By “better” I mean smaller, more efficient, or more maintainable."
Firstly, I'm sure what he's writing there is predicated on the C++ STL being available, the use of which will in turn increase compilation times, because there's a lot of templated code to compile.
I cannot see how you would implement strlen or malloc in C++ (EDIT: as efficiently and/or) more efficiently than C, particularly when you take casting void into account. It's not a far stretch then to imagine writing drivers and so on, where idiomatic C++ would be a distraction compared to C.
In the above his metrics, smaller, more efficient, more maintainable - I can't see any features that C++ has that will allow them to be proven true.
Any program that has to interact with a C library - Stroustroup would suggest library then to be wrapped to make it behave according to C++ style - if so - if the code is just calling a few library functions, C will be shorter and better by all his metrics.
The most convincing is maintainability, but C++ has many more ways to skin a cat than C, so where C had the overhead of understanding someone else's data structure, C++ pretty much does too.
the use of which will in turn increase compilation times
sure, but that does not makes anything he says about it less true. You could even argue it has nothing to do with the discuession at all.
I cannot see how you would implement strlen or malloc in C++ more efficiently than C
He says "C is not more efficient" which means "C++ is as effecient, or more efficient". Which in turns means you are right, and he does not imply you are not (that's the "as efficient" part). Yeeha, you're both right, no need to start a war.
Stroustroup would suggest library then to be wrapped to make it behave according to C++ style
I'd rather think he'd suggest the library should have been written in C++ in the first place. Which is definitely shorter and better by his metrics.
The most convincing is maintainability
which again comes down to the "as efficient" part then.
I am saying that I think that it will take more C++ than C to write malloc or strlen, because of casting to void, so I am saying he's wrong. I could be mistaken however.
I think a wrapper is less of stretch, to suggest that a library be rewritten in C++ as a defence of the simplicity of C++ would suggest a very large amount of cognitive dissonance.
While this is technically true, I have in the past measured this, and the difference on my code when optimising was < 5%, so I think nothing to worry about.
Then of course by moving to a C++ compiler, the temptation is to use features that take forever to compile!
http://tech.slashdot.org/comments.pl?sid=4410261&cid=4533254...
Obviously, what's being compiled is not exactly equivalent but the time difference is startling.
While implementing strlen faster in c++ is harder, implementing qsort faster is easier, as you have the option of compiling a version with the size of type, and comparator, known and inlinable.
Also, you could use a constexpr version of strlen on strings known at compiletime, and be sure the compiker will optimise out the call, unlike in C where you just have to hope the compiler will
Stroustrup made a bold claim that no program exists, I pointed out strlen and malloc - that there exist programs that can be written more efficiently by his metric - your e.g. qsort, I do not dispute, but I refuted his claim. I didn't say implementing strlen faster, I merely said implementing strlen is not by any of his metrics a superior experience in C++.
C would just use hardcoded strings or defines, with sizeof(). This is also a possibility in C++, but I was talking about the implementation of strlen not the usage.
Even the assumption that implementing, e.g., a memory allocation algorithm in C++ is not more comfortable than in C, does no lead to the conclusion that writing a device driver (your example) in C++ is not more comfortable than doing it in C.
But you do admit they are programs! That was all I was trying to do, refute his ridiculous claim - albeit with something marginally less ridiculous. How about a program calling a C library?
The driver thing doesn't automatically lead to the conclusion - but it's not a far stretch to picture it being so. A simple thought exercise does not make a water tight argument.
I can imagine writing certain parts of drivers being better under his metrics in C++ than C but I don't see it in black and white terms like he does. I can see the opposite being the case also.
All that needs to happen for Stroustrup to be wrong is for one program to exist that beats his metrics in C instead of C++.
No, I don't – not in the sense that Stroustrup was using the term "program". strlen or malloc are not programs in the way that this term is commonly understood. His claim is not ridiculous, unless you're nitpicking by using definitions which are just not useful for the discussion at hand (i.e., is C++ better suited for developing non-trivial software).
As for the driver example: I guess we'll just have to agree to disagree, unless someone actually implements a device driver in C and in C++ ;-)
The only project I know of that publishes in multiple languages, vtd-xml - the C++ library has 40k lines of code versus C which is 60k. I don't dispute that C can be more verbose - but it's not a stretch of the imagination to think there's a program somewhere out there that meets Stroustrup's requirements better in C than C++.
Not sure at what point we will have a certain agreement on what is trivial and what isn't. Here's an example of someone writing a lot of code to wrap a C library in to C++, and then doing a few calls to it.
http://www.codeproject.com/Articles/6343/CppSQLite-C-Wrapper...
PS. One of my biggest gripes with C++ is the lack of uniformity. Not only the language itself has insane learning curve, every project does so many trivial and not-so-trivial things differently that it's like learning another language each time you dive into a new codebase. From code formatting, documentation, and source tree layout to error handling, libraries and build system - for something so huge and complicated as C++ there's an amazing number of batteries not included. Even the things that are supposed to be standard in theory are often not so in practice. Damn, there's still custom string classes in the APIs of many popular libraries - almost two decades after std::string and STL!
PPS. And yes, there's a difference between having consistent conventions and trying to be perfect for everybody and everything.
Hardly. Just about every interesting native application is written in C++. Chrome, Photoshop, Cubase, Ableton Live, AutoCad, Java, V8, any AAA video game, etc.
Whether you like C++ or not the fact remains that if you want to write an application of any complexity that really pushes the hardware it's just about your only reasonable choice. Maybe people still write kernels in C but kernels really aren't that complex compared to the applications they run.
BTW: There are many interesting and successful complex applications really pushing the hardware that were not written in C++: Cassandra (Java), Hadoop (Java), PostgreSQL (C), Netty (Java), Nginx (C), TeX/LaTeX (uh, this one is really interesting). So, again, C++ is not the only reasonable choice when performance matters.
When you need maximum performance and minimal latency from a single machine C++ is still the first choice and the number of high-performance apps written in C++ vastly outnumbers those written in C. Check high frequency trading for another example.
The day LLVM gets rewritten in Rust, that day Rust barely starts replacing C++.....