Le retour par référence rvalue est-il plus efficace?

133

par exemple:

Beta_ab&&
Beta::toAB() const {
    return move(Beta_ab(1, 1));
}
Neil G
la source

Réponses:

246
Beta_ab&&
Beta::toAB() const {
    return move(Beta_ab(1, 1));
}

Cela renvoie une référence pendante, tout comme avec le cas de référence lvalue. Après le retour de la fonction, l'objet temporaire sera détruit. Vous devez renvoyer Beta_abpar valeur, comme suit

Beta_ab
Beta::toAB() const {
    return Beta_ab(1, 1);
}

Maintenant, il déplace correctement un Beta_abobjet temporaire dans la valeur de retour de la fonction. Si le compilateur le peut, il évitera complètement le déplacement, en utilisant RVO (optimisation de la valeur de retour). Maintenant, vous pouvez faire ce qui suit

Beta_ab ab = others.toAB();

Et il déplacera la construction du temporaire dans ab, ou fera RVO pour omettre de faire un déplacement ou une copie. Je vous recommande de lire BoostCon09 Rvalue References 101 qui explique le problème et comment (N) RVO interagit avec cela.


Votre cas de renvoi d'une référence rvalue serait une bonne idée dans d'autres occasions. Imaginez que vous ayez une getAB()fonction que vous invoquez souvent de manière temporaire. Il n'est pas optimal de lui faire renvoyer une référence const lvalue pour les temporaires rvalue. Vous pouvez l'implémenter comme ceci

struct Beta {
  Beta_ab ab;
  Beta_ab const& getAB() const& { return ab; }
  Beta_ab && getAB() && { return move(ab); }
};

Notez que movedans ce cas, ce n'est pas facultatif, car il abne s'agit ni d'une valeur automatique locale ni d'une rvalue temporaire. Maintenant, le qualificatif ref && dit que la deuxième fonction est invoquée sur les temporaires rvalue, faisant le mouvement suivant, au lieu de copier

Beta_ab ab = Beta().getAB();
Johannes Schaub - litb
la source
51
J'avais toujours supposé que le problème de référence pendante disparaissait automatiquement lorsque le type de retour était une référence de valeur r. Heureux d'avoir compris ça avant de me mordre. Empilez des bugs effrayants.
deft_code
31
:) Vraiment, les références rvalue ne sont "que des références" comme le sont les références lvalue. ils ne copient ni ne stockent rien.
Johannes Schaub - litb
9
qu'est-ce que le qualificatif const & sur un membre fonctionne plus qu'un simple const?
galinette
4
+ 1-ed, mais lien cassé: BoostCon09 Rvalue References 101
Siu Ching Pong -Asuka Kenji-
3
@galinette Ce sont des qualificatifs de référence .
Malcolm
2

Cela peut être plus efficace, par exemple, dans un contexte un peu différent:

template <typename T>
T&& min_(T&& a, T &&b) {
    return std::move(a < b? a: b);
}

int main() {
   const std::string s = min_(std::string("A"), std::string("B"));
   fprintf(stderr, "min: %s\n", s.c_str());
   return 0;
}

Comme observation intéressante, sur ma machine clang++ -O3génère 54 instructions pour le code ci-dessus contre 62 instructions pour le standard std::min. Cependant, -O0il génère 518 instructions pour le code ci-dessus contre 481 pour le code normal std::min.

merveille.
la source
Je suis confus par votre réponse. J'avais essayé une version similaire (peut-être) mais sans succès : ideone.com/4GyUbZ Pouvez-vous expliquer pourquoi?
Deqing le
Vous avez utilisé une référence sur un objet temporaire for(:)et une intégration sur un objet désalloué. Correction: ideone.com/tQVOal
wonder.mice
3
cette réponse n'est-elle pas vraiment fausse? pour le paramètre de modèle T, T && n'est pas une référence de valeur r, mais plutôt une référence universelle, et pour ce cas, nous devrions toujours appeler std :: forward <T>, pas std :: move! Sans oublier que cette réponse contredit directement la réponse la plus votée ci-dessus.
xdavidliu
@xdavidliu cette réponse est un exemple artificiel comment le retour par rvalue peut être plus efficace. std::move()est simplement utilisé comme une distribution explicite pour illustrer plus clairement le point. Ce n'est pas un code que vous copieriez-coller dans votre projet. Cela ne contredit pas la réponse la plus votée, car un objet temporaire est créé à l'intérieur de la fonction. Ici, l'objet renvoyé est l'un des arguments (les objets temporaires sont détruits lors de la dernière étape de l'évaluation de l'expression complète qui (lexicalement) contient le point où ils ont été créés).
wonder.mice
2
@ wonder.mice alors veuillez remplacer T par std :: string; il n'est pas du tout nécessaire d'utiliser des modèles ici, et utiliser T && comme référence de valeur r est tout simplement un style horrible qui confond inutilement les nouveaux utilisateurs de modèles et de valeurs r.
xdavidliu