Guodong Hu
Guodong Hu

Reputation: 333

Why the temporary object can be returned in this example?

char*[] object can be passed to function version2() & version 3() by the const reference, which means s2 is a temporary object equals to "###" or "@@@".

But why the temporary object s2 can be returned back, while the temporary object temp cannot.

int main()
{
    result = version2(input, "###");
    cout << "Your string enhanced: " << result << endl;

    result = version3(input, "@@@");
    cout << "Your string enhanced: " << result << endl;
    return 0;
}

// No Error
const string & version2(string & s1, const string & s2)
{
    return s2; 
}

// Error
const string & version3(string & s1, const string & s2)
{
    string temp = s2 + s1 + s2;
    return temp;
}

Upvotes: 1

Views: 299

Answers (3)

apple apple
apple apple

Reputation: 10591

I would say it just because the compiler doesn't think version2 is dangerous. Note that for version3, it actually gives a warning, not error (unless you tell it to).

In fact if you change it to catch result by reference, there would still no warning, but the temporary is no doubt have been destroyed. you can check the assembly (or standard), but here I reproduce it and make it easy observable. (although this would be compiler dependent)

wandbox example

If you toggle optimization, you can see output changes and no warning is ever given.


just in case, here is the test code

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


// No Error
auto& f(const string & s){return s;}

int main()
{
    char s[]="#";
    const char* cs = s;
    auto& x = f(cs);
    s[0]='o';
    [[maybe_unused]] auto& y = f(cs);
    cout << x;
}

g++7.2 -Wall -Wextra -std=c++17

Upvotes: 0

songyuanyao
songyuanyao

Reputation: 172924

The point is object life time.

For the 1st case, as you said, a temporary std::string is created and passed to version2 (being bound to the parameter s2). The temporary will be destroyed after the full-expression, i.e. the whole result = version2(input, "###");. That means the reference returned by version2 remains valid, it's fine to use it for assigning to result.

All temporary objects are destroyed as the last step in evaluating the full-expression that (lexically) contains the point where they were created,

For the 2nd case, a local object temp is created inside version3, it will be destroyed when get out of version3. That means version3 will always return a dangled reference. And using it to assign to result leads to UB. The compiler might give a diagnosis for it; but doesn't have to do.

Upvotes: 3

milbrandt
milbrandt

Reputation: 1486

Both versions return a reference to an object.

version2 got a reference from main and return it unmodified back.

version3 defines a local variable temp and want to return a reference to this local. But unfortunately the local does no longer exist as soon as you returned from version3. Thus you would return a reference which would have already been destroyed.

Upvotes: 0

Related Questions