You should write code that is maintainable, compilers are really good at doing the right thing for performance in most cases. If you feel that things go slowly, then measure the performance and after you have located the bottleneck, try to figure out how to improve it.
Up vote 4 down vote favorite 1 share g+ share fb share tw.
In a programme I am writing, I have to pass large data structures (images) between functions. I need my code to be as fast as possible, on different OSs (thus, I can't profile all test cases). I frequently have code of the form... void foo() { ImageType img = getCustomImage(); } ImageType getCustomImage() { ImageType custom_img; //lots of code return custom_img; } AFAIK, the line ImageType img = getCustomImage(); will result in a copy constructor being called for img with the return value from custom_img as its parameter.
Wikipedia says that some compilers will even do this operation again, for an initial temporary variable! My question: Is it faster in general to thus bypass this overhead (copy constructors for images are expensive) by using pass by reference rather than a return value... void foo() { ImageType img; getCustomImage(img); } void getCustomImage(ImageType &img) { //code operating directly on img } I've been told that if the compiler supports return value optimisation then there should be no difference. Is this true?
Can I (within reason) assume this nowadays, and how should I structure my programmes when speed is important c++ return-value-optimization link|improve this question edited Nov 3 '11 at 15:37pst38k43366 asked Nov 3 '11 at 15:32Arrakis1025.
With your mentions of copy constructors and your syntax for the pass by reference in the getCustomImage function signature, this is only applicable to C++. – Vicky Nov 3 '11 at 15:35 Depending on your ImageType constructors, even without return value optimization, the two forms might be more or less equivalent. This is why the only correct answer to "which is faster" is "profile.
" If you can't do all platforms, pick your favorite... the major issues will likely be universally applicable. – Dennis Zickefoose Nov 3 '11 at 15:46 To go off on a tangent, I'd say that a good approach that would sidestep all your worries is to review the definition of ImageType. If that class were to become a small, light-weight handler for dynamically managed storage (say a member vector), and if you use C++11 move semantics, then you could leave your code as it is (return by value) and you'd get good performance out.
– Kerrek SB Nov 3 '11 at 16:11.
You should write code that is maintainable, compilers are really good at doing the right thing for performance in most cases. If you feel that things go slowly, then measure the performance and after you have located the bottleneck, try to figure out how to improve it. You are right in that logically the code triggers different copy constructions: from custom_img to the returned temporary and then to the img object in the caller code, but the fact is that both copies will be elided.
In the particular case of return by value versus default-construct + pass-by-reference, all calling conventions that I know of implement return by value by having the caller allocate the memory and pass a hidden pointer to the callee, which effectively implements what you would be trying to do. So from a performance point of view, they are basically equivalent. I wrote about this (value semantics in function arguments and return values) in the past in this two blog entries: Named Return Value Optimization Copy Elision EDIT: I have intentionally avoided the discussion of the cases where NRVO cannot be applied by the compiler, the reason being that any function f that can take a reference to the object for processing: void f( T & out ) { /* code */ } can be trivially convertible to a function where NRVO is trivial for the compiler to implement that returns by value by a simple transformation into: T f() { T out; /* code */ return out; }.
Like you said, but nobody put it better than Donald Knuth: "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. " :) – Joachim Pileborg Nov 3 '11 at 15:41 @JoachimPileborg: I am not quite sure your quote supports exactly what David said, it's related, but... I expect programmers to identify their own "quirky" ideas as falling into the remaining 3%. – Matthieu M.
Nov 3 '11 at 16:12 I would add that, most of the times, a "default constructed" object does not make sense. The constructor is supposed to initialize the class invariants, and as such most default constructors are errors of design (no better than null pointers: the infamous billion dollars mistake). When you're given an object, you expect it to be ready for use, that's the constructor contract.
Default Constructors (like null pointers) break that contract. And without default constructor, this idiom of "out-parameters" is impossible (they become in/out). – Matthieu M.
Nov 3 '11 at 16:12 @JoachimPileborg: to continue that quote: "Yet we should not pass up our opportunities in that critical 3%. A good programmer will not be lulled into complacency by such reasoning, he will be wise to look carefully at the critical code; but only after that code has been identified. " – Mike Seymour Nov 3 '11 at 16:33 1 @MatthieuM.
Completely agree, and not only that, but even in the cases where the default construction could make sense (think of a function that returns a vector of elements, an empty vector is a correctly fully built object), even in those cases, it complicates the code. The function does not control if the vector passed as reference is empty or not, so to comply with it's post conditions it should handle the non-empty case by clearing, which will require more code to maintain and to execute. – David Rodríguez - dribeas Nov 3 '11 at 23:24.
Since your images are big data structures, I would perhaps suggest that function should return pointers to images. You could use references also (which at the machine level are pointers), but I think pointers fit better for that purpose. I am more familiar with C than with C++, so I could be wrong.
The important issue is when and by whom should your images be de-allocated.
2 If pointers are used, they need to be some sort of smart pointers. – balki Nov 3 '11 at 15:48 @balki: Why?... – James Nov 3 '11 at 16:00 Back to the original question, Qt is a C++ library with a QImage class. – Basile Starynkevitch Nov 3 '11 at 16:06 @James: Because raw pointers invite leaks to dance on your code until it dies horribly.
– Matthieu M. Nov 3 '11 at 16:08 @Matthieu M: I'm wondering about the 'need' part of the claim. – James Nov 3 '11 at 16:26.
At least if you'r targeting reasonably current compilers for the reasonably typical OSes like Windows, MacOS, Linux, or *BSD, you can pretty well count on their implementing RVO/NRVO. IOW, you'd have to look pretty hard to find cases where there was enough difference to care about -- or most likely any at all. Depending on how you're using the data involved, if there is a speed difference, it could just about as easily favor passing/return objects as using a reference.
You might want to read David Abrahams's article about this.
", I generally advise to actually measure for yourself, in your compiler / environment, and then to find out why is that so.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.