Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it faster to return a value or modify a parameter passed by reference?

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

like image 478
Arrakis Avatar asked Nov 03 '11 15:11

Arrakis


3 Answers

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 image 172
David Rodríguez - dribeas Avatar answered Nov 15 '22 14:11

David Rodríguez - dribeas


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.

like image 31
Basile Starynkevitch Avatar answered Nov 15 '22 13:11

Basile Starynkevitch


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.

like image 20
Jerry Coffin Avatar answered Nov 15 '22 13:11

Jerry Coffin