2010-09-15 7 views
28

Considérons ci-dessous.Les références rvalue permettent-elles des références pendantes?

#include <string> 
using std::string; 

string middle_name() { 
    return "Jaan"; 
} 

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

Cela ne calcule rien, mais il compile sans erreur et démontre quelque chose que je trouve déroutant: danger est une référence boiteuse, est-ce pas?

+2

puzzles moi que vous pouvez utiliser && sur le côté gauche du tout, quand cela serait utile? –

+2

@Viktor: Une référence rvalue peut être liée à une variable temporaire et être toujours modifiable. Par exemple 'int && variable_or_dummy = modify_var? move (var): int(); ' – Potatoswatter

+0

Celui que vous appelez un rvalue devient une lvalue donc en danger principal est une lvalue. La valeur ou la lvalueness est une propriété d'une expression. –

Répondre

38

Do références rvalue permettent références ballants?

Si vous vouliez dire « Est-il possible de créer ballants références rvalue » alors la réponse est oui. Votre exemple, cependant,

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 parfaitement bien. La même règle s'applique ici qui rend également this example (article par Herb Sutter) en sécurité. Si vous initialisez une référence avec un pur rvalue, la durée de vie de l'objet tempoary est étendu à la durée de vie de la référence. Vous pouvez toujours produire des références qui pendent, cependant. Par exemple, ce n'est pas plus en sécurité:

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

Parce que std::move renvoie un string&& (qui est pas un pur rvalue) la règle qui prolonge la durée du temps de l'temporaire ne sont pas applicables. Ici, std::move retourne un soi-disant xvalue. Un xvalue est juste une référence rvalue non nommée. En tant que tel, il peut se référer à n'importe quoi et il est fondamentalement impossible de deviner à quoi renvoie une référence renvoyée sans regarder l'implémentation de la fonction.

+4

Excellent exemple de 'move'-ing bien intentionné disparu! – Potatoswatter

+0

@sellibitze serait 'string & danger = std :: move (nom_du_moyen());' être ok? – KitsuneYMG

+1

@kts: Non, ce ne serait pas même compiler parce que vous ne pouvez pas initialiser une référence lvalue non-const avec une expression rvalue. Si vous écrivez 'string const & danger = move (nom_du_moyen()),' cela ne fonctionnera pas non plus. Cela va compiler mais le 'danger' sera une référence qui pendouillera. – sellibitze

3

danger est une référence pendante, n'est ce pas?

Pas plus que si vous aviez utilisé un const &: danger prend possession de la rvalue.

14

références rvalue se lient à rvalues. Un rvalue est soit un prvalue ou un xValue [explanation]. La liaison à la première ne crée jamais de référence pendante, contraignante pour la dernière. C'est pourquoi c'est généralement une mauvaise idée de choisir T&& comme type de retour d'une fonction. std::move est une exception à cette règle.

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

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

+1 Vous avez raison, c'est une bonne règle de ne pas écrire des fonctions qui renvoient des références rvalue. std :: move et std :: forward sont les exceptions évidentes. – sellibitze