0

I was watching a video Curiously Recurring C++ Bugs at Facebook at 14:58 at the code (see in the example I give here) he says that is is hopelessly broken. The reason is that returning reference to a temporary object should not work.

so why it works?

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

const string& get_default(
        const map<string,string>& map,
        const string& key,
        const string& dflt) {

    auto pos = map.find(key);
    return (pos != map.end() ?
                pos->second : dflt);
}

int main()
{
    map<string,string> m;

    auto& value = get_default(m,"whatever","this is the default value");
    cout << value << endl;

    return 0;
}

I understand why I cannot return reference to a local variable (and that fails nicely when I try to print it), but I cannot make this code fail, and I dont know why. I checked google and found that if temporary object is assigned to a reference the temporary objects lifetime will be extended (thats why it is working?). If so why is this code so hopelessy broken?

Using: gcc 7.3.0, c++14

using the comments now I can see how to make it fail: Thanks everyone :)

 int main()
    {
        map<string,string> m;

        auto& value = get_default(m,"whatever","this is the default value"); // const string& value = fails the same way

        string a = "some long string";

        cout << value << endl;//"some long string" will be printed here (this is how it fails - and shows that it is a mess)

        return 0;
    }
Laco
  • 13
  • 3
  • 5
    Undefined behavior is undefined. – scohe001 Oct 04 '18 at 16:44
  • Because destructors of a class type local variables call automatically. When `std::string` or any another object of any class leaving the stack , i.e. just after any function `return` operator or just after the block of code like `.... {std::string s("abc");} ... `. std::string destructor clears the heap memory allocated to store character array, and behavior of your code becomes undefined – Victor Gubin Oct 04 '18 at 16:48
  • first I tried with `const string& value = ` and it worked after I realized there was an `auto&` tried that and it worked too - that's why I dont know how to make it fail. Or it is just an undefined behavior like scohe001 said? – Laco Oct 04 '18 at 16:51
  • @Laco It is undefined behavior. It "works" because you're lucky (or unlucky). It could also crash on you. – NathanOliver Oct 04 '18 at 16:53
  • undefined means - it may or may not work. I.e. if you run-time library operator `new[]/delete []` as well as `malloc/free` not returning previously reserved memory to the operating system back (to be reused for next calls and improve app performance) - it will work, otherwise it may bring to a sigsev/0x0000005 error etc. i.e. C++ standard not specifying what is going to happen when you are accessing a destroyed/uninitialized object. – Victor Gubin Oct 04 '18 at 17:00

1 Answers1

3

The life time of a temporary object is extended only in some contexts. The example in the posted code is not one of those contexts.

int foo() { return 10; }

...

int const& x = foo(); // Life of the temporary is extended.

However,

const int& foo() { return 10; } // Life of the temporary is not extended.

...


int const& x = foo();           // Dangling reference.

Your posted code is analogous to

const int& foo(int const& in) { return in; }

...


int const& x = foo(10);

Here, the reference is valid only inside foo. Once foo returns, the object is not alive any longer, and the reference becomes a dangling reference.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • 1
    The main issue with the OP's code could be better expressed as `const int& foo(const int& f){ return f; } const int& bar = foo(10);`. It is the returning of the temporary bound to the function parameter that is the real issue. – NathanOliver Oct 04 '18 at 16:52
  • @NathanOliver, thanks for that. – R Sahu Oct 04 '18 at 16:58