问题
#include <iostream>
using namespace std;
struct CL
{
CL()
{
cout<<"CL()"<<endl;
}
CL(const CL&)
{
cout<<"CL(const CL&)"<<endl;
}
~CL()
{
cout<<"~CL()"<<endl;
}
};
CL cl;
CL fnc()
{
return cl;
}
int main() {
cout<<"start"<<endl;
const CL& ref=static_cast<const CL&>(fnc());
//...Is "ref" valid here??
cout<<"end"<<endl;
return 0;
}
What's lifetime of temporary object returned by fnc()? Is it lifetime of "ref" or of temporary reference static_cast(fnc()), which destroyed at end of statement?
Output of gcc (lifetime of fnc() is lifetime of "ref"):
CL() //global object "cl"
start
CL(const CL&)
end
~CL()
~CL() //global object "cl"
Output of VS2013 (lifetime of fnc() is lifetime of temporary reference):
CL() //global object "cl"
start
CL(const CL&)
~CL()
end
~CL() //global object "cl"
What's correct by Standard?
回答1:
I believe Visual Studio is correct here, this is covered in defect report #1376 which says:
In a declaration like
T&& r = static_cast<T&&>(T());
it is not clear what the lifetime of the T temporary should be. According to 5.2.9 [expr.static.cast] paragraph 4, the static_cast is equivalent to a declaration of an invented temporary variable t. The lifetime of the temporary is extended to that of t, but it is not clear what that lifetime should be, nor if the subsequent binding of t to r would affect the lifetime of the original temporary. (See also issue 1568.)
and the discussion includes this conclusion:
The reference is bound to the xvalue result of the static_cast, so the lifetime of the temporary is not extended and this example results in a dangling reference.
and defect report 1568 covers this case more specifically:
According to 12.2 [class.temporary] paragraphs 4-5,
There are two contexts in which temporaries are destroyed at a different point than the end of the full-expression...
The second context is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference...
It is not clear whether this applies to an example like the following:
struct S { }; const S& r = (const S&)S();
and the response was:
This issue is a duplicate of issue 1376.
so in this case:
const CL& ref=static_cast<const CL&>(fnc());
the reference is bound to the result of the static_cast
and not to CL
and therefore CL
is a dangling reference.
For reference the relevant text from the draft C++11 standard section 5.2.9
[expr.static.cast]:
Otherwise, an expression e can be explicitly converted to a type T using a static_cast of the form static_- cast(e) if the declaration T t(e); is well-formed, for some invented temporary variable t (8.5). The effect of such an explicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion. The expression e is used as a glvalue if and only if the initialization uses it as a glvalue.
来源:https://stackoverflow.com/questions/29162620/const-reference-to-temporary-reference