6

Consider the following code where I am returning double& and a string&. It works fine in the case of a double but not in the case of a string. Why does the behavior differ?

In both cases the compiler does not even throw the Warning: returning address of local variable or temporary as I am returning a reference.

#include <iostream>
#include <string>
using namespace std;


double &getDouble(){
    double h = 46.5;
    double &refD = h;
    return refD;
}

string &getString(){
    string str = "Devil Jin";
    string &refStr = str;
    return refStr;
}

int main(){
    double d = getDouble();
    cout << "Double = " << d << endl;

    string str = getString();
    cout << "String = " << str.c_str() << endl;

    return 0;
}

Output:

$ ./a.exe
Double = 46.5
String =
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
pankajt
  • 7,642
  • 12
  • 39
  • 60
  • I had a similar post and the answers there were very helpful. Also, check out the comments http://stackoverflow.com/questions/2612709/why-does-this-object-wonk-out-get-deleted – brainydexter Apr 10 '10 at 10:37

4 Answers4

16

You should never return a reference to a local variable no matter what the compiler does or does not do. The compiler may be fooled easily. you should not base the correctness of your code on some warning which may not have fired.

The reason it didn't fire here is probably that you're not literally returning a reference to a local variable, you are returning a variable that is a reference to a local variable. The compiler probably doesn't detect this somewhat more complex situation. It only detects things like:

string &getString(){
    string str = "Devil Jin";
    return str;
}

The case of the double is simpler because it doesn't involve constructing and destructing a complex object so in this situation the flow control analysis of the compiler probably did a better job at detecting the mistake.

shoosh
  • 76,898
  • 55
  • 205
  • 325
  • local to the function, you obviously mean. you're allowed to return a reference to anything outside your scope: member data, function parameters taken as reference etc. – wilhelmtell Apr 10 '10 at 07:44
  • 6
    Actually, I think he says the warning is NOT fired even in the case of the double. So the compiler is fooled in both cases. The reason it works with the double is likely because the location of h on the stack has not been overwritten. Try this: in main store d in a double& then call a couple of other functions, then print d. I bet it doesn't come out right. In all cases though, what you do is "undefined behaviour". There's an excellent lesson in there: just because it gives the right answer doesn't mean that it's done the right way. ;) – Philippe Beaudoin Apr 10 '10 at 07:47
6

The reference to a double refers to a location that is still physically in memory but no longer on the stack. You're only getting away with it because the memory hasn't been overwritten yet. Whereas the double is a primitive, the string is an object and has a destructor that may be clearing the internal string to a zero length when it falls out of scope. The fact that you aren't getting garbage from your call to c_str() seems to support that.

Evan
  • 756
  • 4
  • 9
  • 1
    Honestly all this seems like speculation, and it really doesn't matter. When you return a reference to a local variable the compiler is allowed to do whatever it wants. If it feels like taking a break and going to the kitchen to make itself a sandwich then that is fine too by the standard. So the answer is simple: don't return a reference unless the variable isn't local to the function. – wilhelmtell Apr 10 '10 at 07:40
  • Which is why I said "getting away with it." I'm not supporting the behavior just trying to answer "why?" – Evan Apr 10 '10 at 07:44
  • @wilhelmtell: It is not speculation, it is what will happen. The problem is once you use the return value, as all sorts of bad things can happen: the best thing to happen is your program segfaults; the worst is your program continues to work until it mysteriously misbehaves or segfaults later. – CMircea Apr 10 '10 at 07:45
  • Yes yes, I'm not criticizing your answer, just adding on top of it. Maybe I sounded like I do in my first sentence. :s – wilhelmtell Apr 10 '10 at 07:46
1

GCC used to have an extension called Named Returns that let you accomplish the same thing, but allocated the space outside the function. Unfortunately it doesn't exist anymore; I'm not sure why they took it out

Michael Mrozek
  • 169,610
  • 28
  • 168
  • 175
0

Classic case of a Dangling reference in respect to C++.The double variable was not on call stack while returning reference was trying to access it invoking the compiler to set the guarding flags. String however has explicit Garbage Collection mechanism which lets your compiler to overlook the scenario.