Confused (const std::string& str)


The title is non descriptive and maybe misleading but let me explain it here. First the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <string>

struct S {
	const std::string& str;

	S(const std::string& s) : str(s) {}
};

S MakeS(const std::string& s) {
	return S(s);
}

int main() {
	auto ret = MakeS("ABC");

	std::cout << ret.str << std::endl;
	// Output on windows:	"" <no output>
	// Output on Linux:	"ABC"

	return 0;
}


Is this code valid?
It would seem that expression auto ret = MakeS("ABC"); first calls the constructor for the string "ABC" and then the destructor, corrupting ret.str.

What is actually going on here, and would the correct fix be changing const std::string& str; to const std::string str; <- no reference??

Thank you.
Last edited on
expression auto ret = MakeS("ABC"); first calls the constructor for the string "ABC" and then the destructor, corrupting ret.str.

Yes, the object is destroyed at the end of that expression. MakeS returns a (wrapped) reference, but there is nowhere for the reference to point to!

If you were expecting a lifetime extension, like you get with const string& ret = "ABC";, it does not happen because lifetime extensions are never "passed on". The first reference that got the object (here, the constructor argument) is the one that takes over the lifetime. cppreference has some more detail on the rules here: http://en.cppreference.com/w/cpp/language/reference_initialization#Lifetime_of_a_temporary

(and yes, wrapping the string object rather than a reference to nowhere would make it right.. note that const data members are a little awkward to use, since they kill implicit assignment, I'd just have it std::string str;
Thank you for the reply. I found out that the reason why it worked, is because the original code was something like this:
1
2
3
4
5
6
// some code

Some_function_that_copies_data_members_values(MakeS("entry1"), MakeS("entry2"), ..., MakeS("entryN"));

// At this point all the temporaries are destructed, but not before the end of the function call.
// This is actually quite nice i guess, since there is very little copying involved. 


Thank you for your help.
Topic archived. No new replies allowed.