2

Currently learning about efficiency in C++ and wondered about the efficiency of returning parameters in methods.

Imagine a Vector3f class with an add method.

Code One:

Vector3f Vector3f::add(const Vector3f &rhs) const {
    Vector3f result;
    result.x(x() + rhs.x());
    result.y(y() + rhs.y());
    result.z(z() + rhs.z());
    return result;
}

Code Two:

Vector3f Vector3f::add(const Vector3f &rhs) const {
    return Vector3f(
                x() + rhs.x(),
                y() + rhs.y(),
                z() + rhs.z());
}

I know that the second code segment is more efficient, and I was hoping someone could give me a definitive answer as to why. I'm sure it's something to do with temporary objects.

Cameron Wilby
  • 2,222
  • 1
  • 25
  • 35
  • 6
    If you want to learn about efficiency, learn about using a profiler. For your particular example, any half decent compiler will yield the exact same code for both. – Alexandre C. May 17 '11 at 11:52
  • The main difference I can see is that you're initializing the object through its constructor in the second code sample. – forsvarir May 17 '11 at 11:53
  • 1
    What makes you so sure the second one is "more efficient" ? – Paul R May 17 '11 at 11:54
  • 1
    There is little/no difference. Also, see http://www.agner.org/optimize/ – sehe May 17 '11 at 11:54
  • A good compiler will should make these identical (assuming the setters are just doing the obvious thing and nothing too silly). – Martin York May 17 '11 at 13:09

3 Answers3

5

It probably has to do with the return-value optimisation (RVO). Because the second form constructs the object as it returns it, the compiler is allowed to (and usually will) skip the copy-constructor by constructing the object directly in the caller's context.

The first form can also be optimised in similar fashion, but I've often seen compilers optimise the latter and not the former.

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
  • 1
    There is also the named return value optimization (NRVO) where the compiler is allowed to do the same. If there is a difference here, it is because a specific compiler decides not to apply an optimization. – Bo Persson May 17 '11 at 12:02
  • I remember reading about this now, and this is the correct answer. Thanks! – Cameron Wilby May 17 '11 at 12:05
  • from Stroustrup's CPL 3rd edition (6.3.1 Declarations as Statements [expr.dcl]): `For user-defined types, postponing the definition of a variable until a suitable initializer is available can also lead to better performance.` – davka May 17 '11 at 12:21
  • @Davka - Yes, but here the performance question is not so much about initializing as it is about returning the value. Micro-optimizations still... – Bo Persson May 17 '11 at 12:29
1

Actually, it has more to do with initialization: when you 'default construct' your Vector3f result, the x, y, z members will be initialized. You don't always control the cost of that, especially with 'heavy' members.

Calling a constructor with all member values allows the object to initialize it's members first time right.

But if you really want to save some intermediate steps, you can create a mutator on the class Vector3f, eliminating the need for a temporary:

class Vector3f {
   ...
   Vector3f& operator+=( const Vector3f& other ) {
      x += other.x;
      y += other.y;
      z += other.z;
      return *this;
   }
};

and use it like

Vector3f a( 1,2,3 );
a += Vector3f( 0,0,1 );
xtofl
  • 40,723
  • 12
  • 105
  • 192
  • 1
    They only get initialized if the default-constructor initialize them. If you ask me, that's bad style. There's no reason why "Vector3f v;" should be initialized when "int i;" isn't. It builds an expectation that variables are initialized by default, which is confusing (because the built-in types arent) and leads to degraded performance. – kusma May 17 '11 at 11:57
  • @kusma: if you read Stroustrup's CPL he keeps saying that **all** variables should be initialized on practically every page, so your example of `int i;` is plain bad. – davka May 17 '11 at 12:14
  • I don't see why this is DV'ed, this is the main reason why in general constructing the right value is better than assignment, although in many cases the difference can be optimized out – davka May 17 '11 at 12:16
0

It's fine to wonder how the compilers do things, but I assume you understand there are almost always bigger "fish to fry".

It seems to me lots of people get their ideas about performance from teachers and authors who haven't had much experience with big gnarly real software. I don't know how else to explain the concentration on micro-issues, and that people don't seem to know when they are guessing, even if the guesses are educated.

So, FWIW, here are some common conceptions about performance.

Community
  • 1
  • 1
Mike Dunlavey
  • 40,059
  • 14
  • 91
  • 135