简体   繁体   中英

C++ - Why can you return a reference to a “stack object”

I don't understand how this code works:

class AAA {
public:
    short a, b;
};

AAA &getRef() {
    AAA aaa = {2, 6};
    return aaa;
} // 'aaa' is destroyed here right?

int main() {
    AAA &ref = getRef();
    cout << ref.a << ", " << ref.b << endl;

    cin.ignore();
    return 0;
}

Shouldn't there be an error trying to access ref.a and ref.b ? When I use pointers, I don't get an error either. I mean,this prints "2, 6" every single time .

EDIT: Is it because the memory is still set to those numbers?

It "works" because the memory for aaa hasn't been overwritten when the function returns. If you modify the AAA class to have a destructor that modifies a and b , or if you use some code that writes to the stack, it will almost certainly overwrite the values.

Returning a reference to a local variable is defined by the C++ standard as a "undefined behaviour". The standard often does this in cases where it may, for example, be difficult to determine that the value is indeed stack-based.

For example, consider:

class BBB
{
   AAA& x;
  public:
   BBB(AAA& a) : x(a) {}
   AAA& getX() { return x; }
};

AAA& getReg()
{
   AAA aaa = { 2, 6}
   BBB bbb(aaa);
   return bbb.getX();
}

Most modern compilers will issue a warning for the scenario you have, and some may also give a warning for the code I just wrote. But it's almost certainly possible to come up with some more convoluted case for where it's NOT possible to diagnose this "error".

Unfortunately this is illegal code that invokes undefined behaviour, but it is not flagged as error by the compiler (although it might if more compiler diagnostics are enabled).

It happens to work by accident, presumably because the memory location where the object is created is not re-used for anything else, and is not cleared or overwritten, so you are just "lucky" that the values, once put there, remain.

It seems you want "proof" that it can fail. Maybe try:

int main() {
    AAA &ref = getRef();
    cout << "Hello, world!" << endl;
    cout << ref.a << ", " << ref.b << endl;
}

also, you should enable and pay attention to your compiler's warnings.

Replace the short s with a user-defined type with a complicated destructor (like string ), and you will probably see this crash. Because the memory has been reclaimed, but the old value is still sitting there, you can (sometimes) see the value of built-in types (like int , short , etc.) even after destruction.

[Sample Code]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM