3

Assume there is a method which returns a std::set:

std::set<string> MyClass::myMethod() const
{
   std::set<string> result;
   // ... some code to fill result ...
   return result;
}

In the caller side we can store result of myMethod in two ways:

void MyClass::test()
{
const std::set<string>  s1 = myMethod();  // 1
const std::set<string>& s2 = myMethod();  // 2 (using reference)
// ... some code to use s1 or s2 ...
}

My questions are:

  • Is there any difference between them?
  • Which way is better and efficient?
masoud
  • 55,379
  • 16
  • 141
  • 208

5 Answers5

4
const std::set<string>  s1 = myMethod();  // 1

The return of myMethod is copied into s1. Depending on the size, this could take a long time.

const std::set<string>& s2 = myMethod();  // 2 (using reference)

A reference to the temporary returned by myMethod is stored. This incurs one less copy than the above method, so it is a little faster (assuming no optimizations).

This is a special case feature that is used to make a reference to a variable that would otherwise cease to exist at that ;. This works ONLY if it is a const&, which in your example it is, or an Rvalue reference - && (thanks @Kos).

Community
  • 1
  • 1
Karthik T
  • 31,456
  • 5
  • 68
  • 87
  • Not only `const&`, this applies to `&&` too. – Kos Dec 17 '12 at 09:39
  • @Kos That is a Rvalue reference isnt it.. Im afraid i havent updated myself on move semantics and the related changes yet.. please feel free to edit and add details. – Karthik T Dec 17 '12 at 09:55
  • In C++03, the reference will be (or can be) initialized to refer to a copy, and not to the returned object. Formally, there is no difference between the two. – James Kanze Dec 17 '12 at 10:28
3

Theoretically, the second version is better because it doesn't require the extra copy.

In practice, RVO will likely kick in so they should be about the same.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
2

Yes, these are different:

  1. const std::set<string> s1 = myMethod(); // 1 : copy the temporary object

  2. const std::set<string>& s2 = myMethod(); // 2 (using reference) : the lifetime of the temporary is lengthened, it avoid one copy

See the Guru of the week #88. Note that a compiler can optimize this by making it the same efficiency-wise.

Synxis
  • 9,236
  • 2
  • 42
  • 64
2

There is unlikely to be any difference in practice. I've tested the following with g++ 4.7.2:

#include <string>

extern std::string f();
extern void g(const std::string&, const std::string&);

int main() {
  std::string        x = f();
  const std::string& y = f();
  g(x, y);
}

And it produces identical code for both calls to f():

LEHB0:
        call    __Z1fv
LEHE0:
        leaq    16(%rsp), %rdi
LEHB1:
        call    __Z1fv
LEHE1:
        leaq    16(%rsp), %rsi
NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • 1
    +1 Nice test, And how about portability? Can we trust all C++ compilers to have same output? – masoud Dec 17 '12 at 09:42
  • @MasoudM.: We clearly can't expect *all* compilers to behave in any particular way. However, I'd expect any good compiler to perform this optimization. – NPE Dec 17 '12 at 09:43
  • Which way is better and you usually choose? – masoud Dec 17 '12 at 10:00
  • I'd use the simpler version (i.e. by value) until and unless this shows up during profiling. – NPE Dec 17 '12 at 10:04
1
  1. The first version will create the std::set object, and it will be moved in this line

    const std::set<string> s1 = myMethod();

  2. This will extend the lifetime of the std::set object created in the method :

    const std::set<string>& s2 = myMethod();

Therefore, performance-wise both are doing the same.

BЈовић
  • 62,405
  • 41
  • 173
  • 273