Puis-je réutiliser un paramètre de référence rvalue pour renvoyer une référence rvalue?

Considérons le code suivant:

struct MySsortingng { // some ctors MySsortingng& operator+=( const MySsortingng& other ); // implemented correctly }; MySsortingng operator+( const MySsortingng& lhs, const MySsortingng& rhs ) { MySsortingng nrv( lhs ); nrv += rhs; return nrv; } MySsortingng&& operator+( MySsortingng&& lhs, const MySsortingng& rhs ) { lhs += rhs; return std::move( lhs ); // return the rvalue reference we received as a parameter! } 

Cela fonctionne pour le cas d’utilisation suivant

 MySsortingng a, b, c; // initialized properly MySsortingng result = a + b + c; 

Mais cela crée une référence suspendue pour

 const MySsortingng& result = a + b + c; 

Maintenant, je comprends pourquoi et comment y remédier (renvoyer un ravlue au lieu d’une référence rvalue) mais je considère qu’il s’agit d’une erreur d’utilisation si quelqu’un écrit ce qui précède, car le code semble poser problème. Existe-t-il un exemple “canonique” du monde réel dans lequel l’opérateur ci-dessus renvoyant une référence de valeur est un problème? Quelle est une raison convaincante pour laquelle je devrais toujours renvoyer une valeur aux opérateurs?

L’exemple que vous recherchez est une instruction basée for une plage :

 MySsortingng a, b, c; for( MyCharacter mc : a + b + c ) { ... } 

Dans ce cas, le résultat de a + b + c est lié à une référence, mais le temporaire nested (généré par a + b et renvoyé en tant que référence rvalue par (a + b) + c ) est détruit avant la plage basée sur la boucle est exécutée.

La norme définit les boucles basées sur la plage dans

6.5.4 La plage basée sur l’instruction [stmt.ranged]

1 Pour une déclaration basée for plage

for ( instruction for ( for-range-declaration : expression )

laissez range-init être équivalent à l’ expression entourée de parenthèses

( expression )

et pour une plage basée for énoncé de la forme

for ( instruction for ( for-range-declaration : braced-init-list )

laissez range-init être équivalent à la liste braced-init . Dans chaque cas, une instruction basée for une plage correspond à

 { auto && __range = range-init; for ( auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin ) { for-range-declaration = *__begin; statement } } 

Notez que auto && __range = range-init; prolongerait la durée de vie d’un retour temporaire renvoyé par range-init , mais cela ne prolongerait pas la durée de vie des temporaires nesteds à l’ intérieur de range-init .

Au lieu de demander des ennuis, vous devriez faire confiance au propre constructeur de mouvement de la chaîne:

 MySsortingng operator+(MySsortingng lhs, MySsortingng rhs) { lhs += std::move(rhs); return std::move(lhs); } 

Maintenant, les deux MySsortingng x = a + b; et MySsortingng y = MySsortingng("a") + MySsortingng("b"); travailler efficacement.