F
Frederick Gotham
There is a common misconception, (one which I myself also held at one point),
that a const reference can "extend the lifetime of a temporary". Examples
such as the following are given:
Snippet (1)
-----------
#include <string>
using std::string;
#include <iostream>
using std::cout;
string Func()
{
return "Hello";
}
int main()
{
string const &str = Func();
cout << str << '\n';
}
In the above snippet, no temporary "has had its lifetime extended". If such a
thing were true, then the following code would be perfectly OK:
Snippet (2):
------------
#include <string>
using std::string;
string Func()
{
return "Hello";
}
int main()
{
string const &cstr = Func();
string &str = const_cast<string&>(cstr);
str = "World";
}
But alas, Snippet (2) exhibits undefined behaviour, because the reference
does not refer to the original non-const object which was returned by value
from the function.
The code in Snippet (1) works on exactly the same principle as the following
code snippet:
Snippet (3):
------------
int main()
{
int const &r = 5;
}
In Snippet (1) and in Snippet (3), the const reference remains valid NOT
because a temporary has had its liftime extended, but because the reference
was initialised with an R-value. The C++ Standard defines this process:
If the initializer expression is an rvalue, with T2 a class type, and “cv1
T1” is reference-compatible with “cv2 T2,” the reference is bound in one of
the following ways (the choice is implementation-defined):
— The reference is bound to the object represented by the rvalue (see 3.10)
or to a sub-object within that object.
— A temporary of type “cv1 T2” [sic] is created, and a constructor is called
to copy the entire rvalue object into the temporary. The reference is bound
to the temporary or to a sub-object within the temporary.
This explains why the following code snippet fails to compile, and disproves
that the lifetime of a temporary is extended by binding a const reference to
it.
Snippet (4):
------------
class MyClass {
private:
MyClass(MyClass const &); /* Can't copy-construct! */
public:
MyClass() {}
};
int main()
{
MyClass const &r = MyClass();
}
that a const reference can "extend the lifetime of a temporary". Examples
such as the following are given:
Snippet (1)
-----------
#include <string>
using std::string;
#include <iostream>
using std::cout;
string Func()
{
return "Hello";
}
int main()
{
string const &str = Func();
cout << str << '\n';
}
In the above snippet, no temporary "has had its lifetime extended". If such a
thing were true, then the following code would be perfectly OK:
Snippet (2):
------------
#include <string>
using std::string;
string Func()
{
return "Hello";
}
int main()
{
string const &cstr = Func();
string &str = const_cast<string&>(cstr);
str = "World";
}
But alas, Snippet (2) exhibits undefined behaviour, because the reference
does not refer to the original non-const object which was returned by value
from the function.
The code in Snippet (1) works on exactly the same principle as the following
code snippet:
Snippet (3):
------------
int main()
{
int const &r = 5;
}
In Snippet (1) and in Snippet (3), the const reference remains valid NOT
because a temporary has had its liftime extended, but because the reference
was initialised with an R-value. The C++ Standard defines this process:
If the initializer expression is an rvalue, with T2 a class type, and “cv1
T1” is reference-compatible with “cv2 T2,” the reference is bound in one of
the following ways (the choice is implementation-defined):
— The reference is bound to the object represented by the rvalue (see 3.10)
or to a sub-object within that object.
— A temporary of type “cv1 T2” [sic] is created, and a constructor is called
to copy the entire rvalue object into the temporary. The reference is bound
to the temporary or to a sub-object within the temporary.
This explains why the following code snippet fails to compile, and disproves
that the lifetime of a temporary is extended by binding a const reference to
it.
Snippet (4):
------------
class MyClass {
private:
MyClass(MyClass const &); /* Can't copy-construct! */
public:
MyClass() {}
};
int main()
{
MyClass const &r = MyClass();
}