views:

321

answers:

7

Hi!

is it possible/ok to return a const reference even if the value the function returns is a local variable of this function? i know that locals are not valid anymore once the function returns - but what if the function is inlined and the returned value is only used within the callers scope? then the locals of the function should be included in the callers stackframe, no?

+7  A: 

Don't count on it. Even if this works on 1 compiler, it's not standard supported behavior and is likely to break on others.

dicroce
A: 

The value falls out of scope when the callee falls out of scope. So no, it is gone.

But if you want a fairly ugly solution (and a red flag warning you that your design might need refactoring), you can do something like this:

const MyObj& GetObj()
{
  static const MyObj obj_;
  return obj_;
}

...but this solution if fraught with peril, especially if the object is modifyable, or does something non-trivial in a multithreaded environment.

John Dibling
For unmodifiable objects, this is actually not a bad solution.
Konrad Rudolph
If they're immutable, they can be declared in the outer scope and there's no need to actually return them.
Marcin Seredynski
+4  A: 

inline is not a guarantee -- it's a suggestion. Even if you use tricks to force inline, you'll never be sure about the result, especially if you want to remain portable.

Hence, don't do it.

Kornel Kisielewicz
A: 

The inline keyword doesn't guarantee that the function is really inlined. Don't do it.

Richard Pennington
+4  A: 

No, it's not OK. Local variables are declared on the stack, and the stack keeps changing between method calls. Also, the objects that get out of scope get destroyed. Always return a copy of a local variable.

Consider this code:

#include <iostream>
using namespace std;

class MyClass
{
public:
  MyClass() { cout << "ctor" << endl; }
  ~MyClass() { cout << "dtor" << endl; }
  MyClass(const MyClass& r) { cout << "copy" << endl; }
};

const MyClass& Test()
{
  MyClass m;
  return m;
}

int main()
{
  cout << "before Test" << endl;
  MyClass m = Test();
  cout << "after Test" << endl;
}

This will print out:

before Test
ctor
dtor
copy
after Test
dtor

The object you're trying to copy has already called its destructor and may be in an invalid state.

Marcin Seredynski
+1  A: 
Joe Gauterin
Do you remember where exactly did you learn that C++ stack is delimited by scope?
Marcin Seredynski
No. But destructor calls happen at the scope boundary, not the function boundary, so it seems obvious.
Joe Gauterin
Not really. Destructors get called on the scope boundary, but that doesn't mean that the stack gets winded or unwinded on that boundary. I just had a look in disassebly of a simple app that has 2 scopes nested in another, and saw that nothing happens to the stack pointer. Tried both release and debug builds. Well, I guess the correct answer would be - it's compiler-specific.
Marcin Seredynski
+1  A: 

As others have noted, this is dangerous. It's also unnecessary, if your compiler supports the NRVO (Named Return Value Optimization), and your function uses and returns the local variable you would have liked to return by ref in a fairly simple way.

The NRVO allows the compiler to avoid copy construction under certain conditions - typically the main reason to avoid returning objects by value. VC++ 8 supports this (a delta on previous revisions) and it makes quite a bit of perf diff in frequently used code.

Steve Townsend