2010-09-15 12 views
28

Considere lo siguiente.¿Las referencias rvalue permiten referencias colgantes?

#include <string> 
using std::string; 

string middle_name() { 
    return "Jaan"; 
} 

int main() 
{ 
    string&& danger = middle_name(); // ?! 
    return 0; 
} 

Esto no calcula nada, pero se compila sin error y demuestra algo que me resulta confuso: danger es una referencia colgando, ¿verdad?

+2

me desconcierta que puede usar && en el lado izquierdo en absoluto, ¿cuándo sería útil? –

+2

@Viktor: una referencia rvalue puede vincularse a un temporal y seguir siendo modificable. Ej 'int && variable_or_dummy = modify_var? move (var): int(); ' – Potatoswatter

+0

Al nombrar un valor r, se convierte en un valor l, por lo que en el' peligro 'principal es un valor l. la validez o valor es propiedad de una expresión –

Respuesta

38

¿Las referencias rvalue permiten referencias colgantes?

Si quiso decir "¿Es posible crear referencias de valores r pendientes?", La respuesta es sí. Su ejemplo, sin embargo,

string middle_name() { 
    return "Jaan"; 
} 

int main() 
{ 
    string&& nodanger = middle_name(); // OK. 
    // The life-time of the temporary is extended 
    // to the life-time of the reference. 
    return 0; 
} 

está perfectamente bien. Aquí se aplica la misma regla que hace que this example (artículo de Herb Sutter) también sea seguro. Si inicializa una referencia con pure rvalue, la vida útil del objeto temporal se amplía a la duración de la referencia. Sin embargo, todavía puedes producir referencias colgantes. Por ejemplo, esto ya no es seguro:

int main() 
{ 
    string&& danger = std::move(middle_name()); // dangling reference ! 
    return 0; 
} 

Debido std::move devuelve un string&& (que es no un pura rvalue) la regla que se extiende de por vida del temporal no se aplica. Aquí, std::move devuelve un llamado xvalue. Un xvalue es solo una referencia rvalue sin nombre. Como tal, podría referirse a cualquier cosa y es básicamente imposible adivinar a qué se refiere una referencia devuelta sin mirar la implementación de la función.

+4

¡Excelente ejemplo de 'movimiento' bien intencionado que salió mal! – Potatoswatter

+0

@sellibitze would 'string & danger = std :: move (middle_name());' estar bien? – KitsuneYMG

+1

@kts: No. Ni siquiera compilaría porque no puede inicializar una referencia lvalue no const con una expresión rvalue. Si escribe 'string const & danger = move (middle_name());' tampoco funcionará. Se compilará, pero "peligro" será una referencia pendiente. – sellibitze

3

danger es una referencia pendiente, ¿no?

No

más que si se hubiera usado un const &: danger toma posesión del valor de lado derecho.

14

Las referencias rvalue se unen a los valores de r. Un valor r es prvalue o xvalue [explanation]. Vinculación con el primero nunca crea una referencia oscilante, vinculante para el último poder. Es por eso que generalmente es una mala idea elegir T&& como el tipo de devolución de una función. std::move es una excepción a esta regla.

T& lvalue(); 
T prvalue(); 
T&& xvalue(); 

T&& does_not_compile = lvalue(); 
T&& well_behaved = prvalue(); 
T&& problematic = xvalue(); 
+0

+1 Tienes razón, es una buena regla general no escribir funciones que devuelvan referencias rvalue. std :: move y std :: forward son las excepciones obvias. – sellibitze

Cuestiones relacionadas