1

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;
}
milbrandt
  • 1,438
  • 2
  • 15
  • 20
Guodong Hu
  • 303
  • 1
  • 2
  • 11

3 Answers3

3

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.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • Thank you. But for the 1st case who actually creates the temporary object and who decides when it will be destroyed. I’m new with C++, and the book I’m learning (C++ primer plus) says little about this. So could you please recommend some books or blogs? Thank you. – Guodong Hu Mar 30 '18 at 09:56
  • In the 1st case, the temporary is created as part of the function call, before the function body begins and destroyed after it ends; that's basically all you need to know (and for everything else, you can check the assembly). Also, we have a thread around here for books, so you can search for that. – underscore_d Mar 30 '18 at 09:59
  • @LeoHu I would suggest cppreference.com (as I linked in my answer), and you can find a good book from [The Definitive C++ Book Guide and List](https://stackoverflow.com/q/388242/3309790). – songyuanyao Mar 30 '18 at 10:00
0

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.

milbrandt
  • 1,438
  • 2
  • 15
  • 20
0

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

apple apple
  • 10,292
  • 2
  • 16
  • 36