2

What is the difference between these?

MyType myFunction();

MyType t = myFunction();

AND

MyType &myFunction();

MyType t = myFunction();

AND

const MyType &myFunction();

MyType t = myFunction();

What is going on behind the scenes?

lucian.pantelimon
  • 3,673
  • 4
  • 29
  • 46
Cheetah
  • 13,785
  • 31
  • 106
  • 190

4 Answers4

3

In the three cases the second line is common:

MyType t = myFunction();

That line gets the result of calling myFunction and uses it to copy-construct a new element of MyType called t.

Now on the differences. In the first case you are returning by value, which means that (semantically), the compiler will create a copy of the object that is in the return statement inside myFunction and then use that copy as the source for the copy construction of t. The compiler will most probably elide the copies (at least the second).

In the other two cases, the functions return references to some other object. If the objects are locals, then it is Undefined Behavior. The difference between the two is whether the reference returned can be used to modify the referred object or not, and this might impact what copy constructor is used or if it can be used at all. Beware that the object from which you are obtaining the reference must outlive the function call, or you will be causing undefined behavior.

// an example where it matters:
typedef std::auto_ptr<int> MyType;
MyType t = myFunction();

Because std::auto_ptr modifies the right hand side on assignment, the previous code will only work if the returned reference is non-const.

Luchian points out that returning a reference will most likely be undefined behavior, so when would it not be? When the object from which the reference was obtained outlives the uses of the reference. That is the basic building block of the Meyers singleton:

// an example where returning a reference is correct
MyType & myFunction() {
  static MyType instance;   // Note static storage duration!
  return instance;
}

Or any plain accessor that returns a reference to a subobject. Some of the common cases are operator[] in containers (they usually don't copy the value, but return a reference to the stored data).

But it is true that more often than not, functions don't return statically lived objects, but rather locals.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • In addition to the Meyers singleton (which doesn't enjoy universal adhesion, for various reasons), you might site functions like the `[]` operators in `std::vector` and `std::map`. They're probably more frequent examples of where references are used for return values. – James Kanze Mar 26 '12 at 12:37
  • @JamesKanze: Right, there are many *accessors* in classes that should return references. I was trying to limit the response to free functions as that seems to be the case of the question. Will update the answer to contain that particular example. Thanks. – David Rodríguez - dribeas Mar 26 '12 at 13:12
1

I'm assuming these are free functions.

MyType myFunction();
MyType t = myFunction();

returns a MyType object by value. Theoretically, the object created inside myFunction is copied on return. Practically, RVO will most likely occur.

MyType &myFunction();
MyType t = myFunction();

returns by reference. This will most likely be undefined behavior, since it's illegal to return local objects by reference. However, if myFunctions is a member function, you could return a MyType that is a member of the class and it would be ok, as long as the instance outlives t.

For the second code snippet, you should get a warning - "returning local variable by reference" or something similar.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • @OliCharlesworth yeah, sorry bout that. I corrected it immediately. – Luchian Grigore Mar 26 '12 at 11:28
  • "it's illegal to return local objects by reference"...so how should I return an object created within the function? – Cheetah Mar 26 '12 at 11:29
  • @Ben by value - like the first snippet. – Luchian Grigore Mar 26 '12 at 11:30
  • @Ben You can return a reference to an object created by the function (or perhaps a search result), as long as the object is stored somewhere else. A value local to the function disappears when the function returns, so it has to be returned by value. – Bo Persson Mar 26 '12 at 11:34
  • @Luchian would that work? Does it copy all the member values of MyType?...is that an efficient way to do things? – Cheetah Mar 26 '12 at 11:35
  • 1
    @Ben - Returning a local variable is actually *very* efficient, as the compiler is allowed to avoid the copying and construct the result directly in `t`. See [Do C++ compilers avoid copying when returning by value?](http://stackoverflow.com/questions/8228759/do-c-compilers-avoid-copying-when-returning-by-value) – Bo Persson Mar 26 '12 at 11:41
  • @Ben I mentioned RVO in my answer, you should read up on that. – Luchian Grigore Mar 26 '12 at 11:45
  • @Ben - it depends on whether you want the returned copy to be used and automatically destroyed, or to live until somebody deletes it explicitly. Autodestroy - return by value. Longer lived - allocate it on the heap and return a pointer. – Jirka Hanika Mar 26 '12 at 11:48
0

Most answers get things correct save for one little detail.

const MyType& t = myFunction();

It would seem that if myFunction() returns a temporary variable this would be undefined behavior, but in reality it's not. This is not UB, and in fact the const reference extends the lifetime of the temporary to the lifetime of the const reference. In fact this is the one version with most potential for compiler optimization and also gives away an important lesson, that one should always take return values into a const reference when possible.

Ylisar
  • 4,293
  • 21
  • 27
  • I'm not sure what you're trying to say here. If `myFunction()` returns a value, then it is a temporary. Always. And while the lifetime of the temporary (or of a copy of it, in C++03) may be extended, there's absolutely no reason to not use `MyType t = myFunction()` here. If `myFunction()` returns a reference, it's undefined behavior, regardless of what you do with the return value. – James Kanze Mar 26 '12 at 12:40
  • Yeah in hindsight I see that I'm the fool as I missed the function sig. But basically if `MyType myFunction();` then `const MyType& t = myFunction();` is both valid and preferred. `MyType t = myFunction();` with the above signature is more likely to do an often unnecessary temporary ( without going into the specifics of RVO & NRVO ). – Ylisar Mar 26 '12 at 12:48
  • 1
    More or less. If `myFunction()` returns by value, there's no sense in not using it to initialize a value; making the local variable a reference type is just extra noise. If `myFunction()` returns a reference, allowing polymorphism or (if non-const) modification of the object (which exists elsewhere), it could easily make sense to use a local reference, to avoid having to recall the function each time you access the object. – James Kanze Mar 26 '12 at 12:53
  • I could've sworn `MyType t( myFunction() );` would be an extra copy, but using a trivial example it would seem it's not so you're probably correct. – Ylisar Mar 26 '12 at 13:46
  • In both cases (at least in C++03), an extra copy is allowed. I've yet to encounter a compiler that makes it, in either case (but because it is allowed, the object must be copiable). – James Kanze Mar 26 '12 at 15:35
-1

I guess what you want to do is something like:

MyType *myFuntion()
{
  MyType *t = new MyType;
  // do something with t
  return t;
}

// ... somewhere else ...
MyType *t = myFunction();

i.e. you construct a new object inside a function and return a pointer to it. Don't forget to call

 delete t;

somewhere later!

BenMorel
  • 34,448
  • 50
  • 182
  • 322
steffen
  • 8,572
  • 11
  • 52
  • 90