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 (
instructionfor (
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 (
instructionfor (
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.