I'm studying the rvalue reference concept in C . I want to understand if the following code can create a dangling reference.
std::string&& s = std::move("test text");
std::cout << s << std::endl;
From my understanding, s
should be a dangling reference because its assignment it binds to a return value of std::move
. And the correct usage should be std::string&& s = "test text"
. But when I tried it on here http://cpp.sh/ the program actually runs and prints "test text". Does this mean s
is actually not a dangling reference?
I found a similar stack overflow question here:
int main()
{
string&& danger = std::move(middle_name()); // dangling reference !
return 0;
}
which confirms that this will lead to dangling reference. Can anyone give some hints? Thanks!
CodePudding user response:
No it does not.
From my understanding, s should be a dangling reference because its assignment it binds to a return value of
std::move
You have looked at the value categories, but not at the types.
The type of "test text"
is char const[10]
. This array reside in const global data.
You then pass it to move, which will return an rvalue reference to the array. The return type of this move cast expression is char const(&&)[10]
, an xvalue to a character array.
Then, this is assigned to a std::string&&
. But this is not a string, but a character array. A prvalue of type std::string
must then be constructed. It is done by calling the constructor std::string::string(char const*)
, since the reference to array will decay into a pointer when passing it around.
Since the reference is bound to a materialized temporary which is a prvalue, lifetime extension of the reference apply.
The std::move
is completely irrelevant and does absolutely nothing in this case.
So in the end your code is functionally equivalent to this:
std::string&& s = std::string{"test text"};
std::cout << s << std::endl;
The answer would be difference if you would have used a std::string
literal:
// `"test text"s` is a `std::string` prvalue
std::string&& s = std::move("test text"s);
std::cout << s << std::endl;
In this case, you have a prvalue that you send to std::move
, which return an xvalue of type std::string
, so std::string&&
.
In this case, no temporary is materialized from the xvalue
return by std::move
, and the reference simply bind to the result of std::move
. No extension is applied here.
This code would be UB, like the example you posted.
CodePudding user response:
the program actually runs and prints "test text". Does this mean s is actually not a dangling reference?
No. Program running and printing "test text" does not mean that the program doesn't have a dangling reference. It is possible for a program to have that behaviour even when there is a dangling reference.
I found a similar stack overflow question here: ... which confirms that this will lead to dangling reference.
It confirms no such thing, because the linked question is different.
There is no dangling reference in the example. The string literal is an lvalue to an array of const char. The array has static storage duration, and a reference to the array will remain valid through the entire program.