web-dev-qa-db-fra.com

Déplacer avec vector :: Push_back

Supposons que j'ai le code suivant:

#include <vector>
struct A {
    int a;
    int x;
};
int main() {
    using namespace std;
    A a1;
    A a2;
    vector<A> va;
    va.Push_back(a1);
    va.Push_back(move(a2));
}

Je suis conscient que les éléments de std :: vector sont stockés de manière contiguë, contrairement à std :: list. Dans le code ci-dessus, a2 est déplacé, mais n'y a-t-il pas vraiment de copie de a2 dans le vecteur va? Quelle est la différence entre va.Push_back(a2); et va.Push_back(move(a2));?

25
ggg

Dans votre cas, il n'y a pas de différence réelle puisque vous utilisez des constructeurs de copie fournis par le compilateur. Vous constateriez une différence de performance notable lorsque vous utilisez des objets constructibles par déplacement, ce qui demande beaucoup d’efforts de copie. Dans ce cas, utiliser Push_back(x) créerait une copie de l'objet, alors que Push_back(move(x)) indiquerait à Push_back() qu'il peut "voler" le contenu de x, laissant x dans un état inutilisable et indéfini.

Considérez si vous aviez un vecteur de listes (std::vector<std::list<int> >) et que vous vouliez envoyer une liste contenant 100 000 éléments. Sans move(), la structure de liste entière et tous les 100 000 éléments seront copiés. Avec move(), certains pointeurs et autres petits morceaux de données sont mélangés, et c'est à peu près tout. Ce sera beaucoup plus rapide et nécessitera moins de consommation de mémoire globale.

35
cdhowie

Lorsque vous utilisez va.Push_back(a2) version vector<T>::Push_back(const T&) sera appelée, lorsque vous utiliserez va.Push_back(move(a2)) version vector<T>::Push_back(T&&) sera appelée ...

Mais dans votre cas, il n'y a pas de différence de performance, puisque

15 Le constructeur copier/déplacer défini implicitement pour une classe non-union X effectue une copie/un déplacement membre par membre de ses bases et membres.

Paragraphe 12.8 n3337 projet.

16
ForEveR

Je veux noter quelque chose que d’autres réponses n’ont pas passé; est que la ?.Push_back(move(?)) sera plus lente que la ?.Push_back(?) dans votre cas (lorsque vous avez des objets copiables de manière triviale), car le constructeur de déplacement doit mettre à zéro\définir l'objet déplacé, ce qui revient à écrire/copier deux objets.

0
LyingOnTheSky