web-dev-qa-db-fra.com

Renvoyer std :: vector avec std :: move

J'ai une question très basique: est-ce une bonne idée de retourner un std::vector<A> en utilisant std::move? Par exemple:

class A {};
std::vector<A> && func() {
    std::vector<A> v;
    /* fill v */
    return std::move(v);
}

Dois-je revenir std::map, std::list .. etc ... de cette façon?

13
Koban

Vous déclarez une fonction à renvoyer par référence de valeur r - cela ne devrait presque jamais être fait (si vous retournez l'objet local par référence, vous vous retrouverez avec une référence pendante). Au lieu de cela, déclarez la fonction à renvoyer par valeur. De cette façon, la valeur de l'appelant sera déplacée par la valeur r renvoyée par la fonction. La valeur retournée sera également liée à toute référence.

Deuxièmement, non, vous ne devez pas retourner en utilisant un std::move car cela empêchera le compilateur d'utiliser RVO . Il n'y a pas besoin car le compilateur convertira automatiquement toute référence de valeur l retournée en référence de valeur r si possible.

std::vector<A> func() {
    std::vector<A> v;
    /* fill v */
    return v; // 'v' is converted to r-value and return value is move constructed.
}

Plus d'informations:

18
Snps

Non, ça ne l'est pas. Cela empêchera en fait la suppression de la copie dans certains cas. Il y a même un avertissement dans certains compilateurs à ce sujet, appelé -Wpessimizing-move.

Comme les réponses avant moi, il suffit de le renvoyer par valeur, en changeant simplement le type de retour std::vector<A>, et le compilateur se chargera d'appeler le constructeur de déplacement si nécessaire.

Vous pouvez jeter un oeil à ce post que je viens de trouver, qui semble l'expliquer en détail (bien que je ne l'ai pas lu moi-même): https://vmpstr.blogspot.hu/2015/12/ redundant-stdmove.html

1
Attila

Les compilateurs gcc et clang avec optimisation activée génèrent le même code binaire dans les deux cas lorsque vous renvoyez une variable locale et lorsque vous écrivez std::move(). Renvoyez simplement une valeur.

Mais en utilisant && et noexcept spécificateur est utile si vous créez un constructeur en mouvement et en déplaçant operator= pour votre classe personnalisée

0
knst