c++ - const referencia a referencia temporal
reference language-lawyer (1)
#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;
}
¿Qué duración tiene el objeto temporal devuelto por fnc ()? ¿Es la vida útil de "ref" o de referencia temporal static_cast (fnc ()), que se destruyó al final de la instrucción?
Salida de gcc (la vida útil de fnc () es el tiempo de vida de "ref"):
CL() //global object "cl"
start
CL(const CL&)
end
~CL()
~CL() //global object "cl"
Salida de VS2013 (la duración de fnc () es la vida de referencia temporal):
CL() //global object "cl"
start
CL(const CL&)
~CL()
end
~CL() //global object "cl"
¿Qué es correcto según el estándar?
Creo que Visual Studio es correcto aquí, esto está cubierto en el informe de defectos # 1376 que dice:
En una declaración como
T&& r = static_cast<T&&>(T());
no está claro cuál debería ser la vida del T temporal. De acuerdo con 5.2.9 [expr.static.cast] párrafo 4, static_cast es equivalente a una declaración de una variable temporal inventada t. La vida útil de lo temporal se extiende a la de t, pero no está claro qué duración debería tener, ni si la vinculación posterior de t a r afectaría la duración del temporal original. (Ver también el número 1568.)
y la discusión incluye esta conclusión:
La referencia está vinculada al resultado xvalue de static_cast, por lo que la vida útil del temporal no se extiende y este ejemplo da como resultado una referencia colgante.
y el informe de defectos 1568 cubre este caso más específicamente:
De acuerdo con 12.2 [class.temporary], párrafos 4-5,
Hay dos contextos en los que los temporales se destruyen en un punto diferente al final de la expresión completa ...
El segundo contexto es cuando una referencia está vinculada a un temporal. El temporal al que está vinculada la referencia o el temporal que es el objeto completo de un subobjeto al que está vinculada la referencia persiste durante el tiempo de vida de la referencia ...
No está claro si esto se aplica a un ejemplo como el siguiente:
struct S { }; const S& r = (const S&)S();
y la respuesta fue:
Este problema es un duplicado del número 1376.
entonces en este caso:
const CL& ref=static_cast<const CL&>(fnc());
la referencia está ligada al resultado del static_cast
y no a CL
y, por lo tanto, CL
es una referencia colgante.
Para referencia, el texto relevante del borrador de C ++ 11 estándar sección 5.2.9
[expr.static.cast] :
De lo contrario, una expresión e puede convertirse explícitamente a un tipo T usando una static_cast de la forma static_-cast (e) si la declaración T t (e); está bien formado, por alguna variable temporal inventada t (8.5). El efecto de tal conversión explícita es lo mismo que realizar la declaración y la inicialización y luego usar la variable temporal como resultado de la conversión. La expresión e se usa como un glvalue si y solo si la inicialización lo usa como un glvalue.