push_back vs emplace_back

Je suis un peu confus en ce qui concerne la différence entre push_back et emplace_back .

 void emplace_back(Type&& _Val); void push_back(const Type& _Val); void push_back(Type&& _Val); 

Comme il y a une surcharge push_back prenant une référence de valeur, je ne vois pas très bien à quoi emplace_back ?

En plus de ce que le visiteur a dit:

La fonction void emplace_back(Type&& _Val) fournie par MSCV10 n’est pas conforme et redondante, car comme vous l’avez noté, elle est ssortingctement équivalente à push_back(Type&& _Val) .

Mais la vraie forme C ++ 0x de emplace_back est vraiment utile: void emplace_back(Args&&...) ;

Au lieu de prendre un value_type il prend une liste value_type d’arguments, ce qui signifie que vous pouvez maintenant parfaitement transférer les arguments et construire directement un object dans un conteneur sans aucun temporaire.

C’est utile parce que, peu importe l’intelligence que RVO et la sémantique déplacent, il y a encore des cas compliqués où un push_back est susceptible de faire des copies inutiles (ou de se déplacer). Par exemple, avec la fonction insert() traditionnelle d’un std::map , vous devez créer un fichier temporaire, qui sera ensuite copié dans un std::pair , qui sera ensuite copié dans la carte:

 std::map m; int anInt = 4; double aDouble = 5.0; std::ssortingng aSsortingng = "C++"; // cross your finger so that the optimizer is really good m.insert(std::make_pair(4, Complicated(anInt, aDouble, aSsortingng))); // should be easier for the optimizer m.emplace(4, anInt, aDouble, aSsortingng); 

Alors, pourquoi n’ont-ils pas implémenté la bonne version de emplace_back dans MSVC? En fait, il y a eu un bug il y a quelque temps déjà, alors j’ai posé la même question sur le blog Visual C ++ . Voici la réponse de Stephan T Lavavej, le responsable officiel de l’implémentation de la bibliothèque standard Visual C ++ chez Microsoft.

Q: Les fonctions bêta 2 emplace sont-elles juste un type de placeholder en ce moment?

R: Comme vous le savez peut-être, les modèles variadiques ne sont pas implémentés dans VC10. Nous les make_shared() avec des machines de préprocesseur pour des choses comme make_shared() , tuple et les nouveautés de . Cette machine de préprocesseur est relativement difficile à utiliser et à entretenir. En outre, cela affecte considérablement la vitesse de compilation, car nous devons inclure à plusieurs resockets des sous-titres. En raison d’une combinaison de contraintes de temps et de problèmes de vitesse de compilation, nous n’avons pas simulé de modèles variadiques dans nos fonctions emplace.

Lorsque des modèles variadiques sont implémentés dans le compilateur, vous pouvez vous attendre à en tirer parti dans les bibliothèques, y compris dans nos fonctions emplace. Nous prenons très au sérieux la conformité, mais malheureusement, nous ne pouvons pas tout faire en même temps.

C’est une décision compréhensible. Tous ceux qui n’ont essayé qu’une seule fois d’émuler un modèle variadic avec des trucs horribles de préprocesseur savent à quel point ces choses sont dégoûtantes.

emplace_back ne doit pas utiliser un argument de type vector::value_type , mais plutôt des arguments variadiques qui sont transmis au constructeur de l’élément ajouté.

 template  void emplace_back(Args&&... args); 

Il est possible de passer un value_type qui sera transmis au constructeur de la copie.

Comme il transfère les arguments, cela signifie que si vous n’avez pas la valeur rvalue, cela signifie que le conteneur stockera une copie “copiée”, et non une copie déplacée.

  std::vector vec; vec.emplace_back(std::ssortingng("Hello")); // moves std::ssortingng s; vec.emplace_back(s); //copies 

Mais ce qui précède doit être identique à ce que fait push_back . Il est probablement plutôt destiné à des cas d’utilisation comme:

  std::vector > vec; vec.emplace_back(std::ssortingng("Hello"), std::ssortingng("world")); // should end up invoking this constructor: //template pair(U&& x, V&& y); //without making any copies of the ssortingngs 

L’optimisation pour emplace_back peut être démontrée dans l’exemple suivant.

Pour emplace_back constructeur A (int x_arg) sera appelé. Et pour push_back A (int x_arg) est appelé en premier et move A (A &&rhs) est appelé après.

Bien sûr, le constructeur doit être marqué explicit , mais pour l’exemple actuel, il est bon de supprimer le caractère explicite.

 #include  #include  class A { public: A (int x_arg) : x (x_arg) { std::cout << "A (x_arg)\n"; } A () { x = 0; std::cout << "A ()\n"; } A (const A &rhs) noexcept { x = rhs.x; std::cout << "A (A &)\n"; } A (A &&rhs) noexcept { x = rhs.x; std::cout << "A (A &&)\n"; } private: int x; }; int main () { { std::vector a; std::cout << "call emplace_back:\n"; a.emplace_back (0); } { std::vector a; std::cout << "call push_back:\n"; a.push_back (1); } return 0; } 

sortie:

 call emplace_back: A (x_arg) call push_back: A (x_arg) A (A &&) 

emplace_back mise en œuvre conforme enverra les arguments au constructeur vector::value_type lorsqu’il est ajouté au vecteur. Je me souviens que Visual Studio ne prenait pas en charge les modèles variadic, mais que les modèles variadic seraient pris en charge dans Visual Studio 2013 RC. Je suppose donc qu’une signature conforme sera ajoutée.

Avec emplace_back , si vous transférez les arguments directement dans le constructeur vector::value_type , vous n’avez pas besoin qu’un type soit déplaçable ou copiable pour la fonction emplace_back , à proprement parler. Dans le cas du vector , ceci n’est pas utile, car le vector::value_type besoin d’un type copiable ou mobile pour se développer.

Mais notez que cela pourrait être utile pour std::map , car une fois que vous atsortingbuez une entrée dans la map, elle n’a plus besoin d’être déplacée ou copiée, contrairement à vector , ce qui signifie que vous pouvez utiliser std::map efficacement avec un type mappé qui n’est ni copiable ni mobile.

Un de plus en cas de listes:

// construit les éléments en place.
emplace_back (“element”);

// Il va créer un nouvel object, puis copier (ou déplacer) sa valeur d’arguments. push_back (explicitDataType {“element”});

Un joli code pour push_back et emplace_back est affiché ici.

http://fr.cppreference.com/w/cpp/container/vector/emplace_back

Vous pouvez voir l’opération de déplacement sur push_back et non sur emplace_back.