Je suis un peu confus quant à 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 push_back
surcharge prenant une référence rvalue, je ne vois pas vraiment à quoi sert le but emplace_back
?
template <class _Valty> void emplace_back(_Valty&& _Val)
version qui prend une référence universelle qui fournit une transmission parfaite auxexplicit
constructeurs à argument unique.push_back
est préférableemplace_back
? Le seul cas auquel je peux penser est si une classe était en quelque sorte copiable (T&operator=(constT&)
) mais pas constructible (T(constT&)
), mais je ne vois pas pourquoi on voudrait jamais ça.Réponses:
En plus de ce que le visiteur a dit:
La fonction
void emplace_back(Type&& _Val)
fournie par MSCV10 est non conforme et redondante, car comme vous l'avez noté, elle est strictement équivalente àpush_back(Type&& _Val)
.Mais la vraie forme C ++ 0x de
emplace_back
est vraiment utilevoid emplace_back(Args&&...)
:;Au lieu de prendre un,
value_type
il prend une liste variadique d'arguments, ce qui signifie que vous pouvez maintenant parfaitement transmettre les arguments et construire directement un objet dans un conteneur sans aucun temporaire.C'est utile parce que, quelle que soit l'intelligence RVO et le déplacement sémantique apportés à la table, 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
insert()
fonction traditionnelle de astd::map
, vous devez créer un temporaire, qui sera ensuite copié dans unstd::pair<Key, Value>
, qui sera ensuite copié dans la carte:Alors pourquoi n'ont-ils pas implémenté la bonne version de emplace_back dans MSVC? En fait, cela m'a trop dérangé il y a un certain temps, j'ai donc 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.
C'est une décision compréhensible. Tous ceux qui ont essayé une seule fois d'émuler un modèle variadic avec des trucs horribles de préprocesseur savent à quel point ce truc est dégoûtant.
la source
pair<const int,Complicated>
n'a pas de constructeur qui prend un int, un autre int, un double et comme 4ème paramètre une chaîne. Cependant, vous pouvez directement construire cet objet paire à l'aide de son constructeur par morceaux. La syntaxe sera bien sûr différente:m.emplace(std::piecewise,std::forward_as_tuple(4),std::forward_as_tuple(anInt,aDouble,aString));
emplace_back
tant qu'il a été implémenté dans Visual C ++ lorsque des modèles variadicemplace_back
ne doit pas prendre un argument de typevector::value_type
, mais plutôt des arguments variadiques qui sont transmis au constructeur de l'élément ajouté.Il est possible de passer un
value_type
qui sera transmis au constructeur de copie.Parce qu'il transmet les arguments, cela signifie que si vous n'avez pas rvalue, cela signifie toujours que le conteneur stockera une copie "copiée", pas une copie déplacée.
Mais ce qui précède devrait être identique à ce qui le
push_back
fait. Il est probablement plutôt destiné à des cas d'utilisation tels que:la source
s
portée déplacée , n'est-ce pas dangereux?vec.emplace_back("Hello")
fonctionnera, puisque l'const char*
argument sera transmis austring
constructeur. C'est tout l'intérêt deemplace_back
.std::vector
. Un videstd::vector
est un état valide, mais vous ne pouvez pas l'invoquerfront()
. Cela signifie que toute fonction qui n'a pas de conditions préalables peut toujours être appelée (et les destructeurs ne peuvent jamais avoir de conditions préalables).L'optimisation pour
emplace_back
peut être démontrée dans l'exemple suivant.Pour
emplace_back
constructeurA (int x_arg)
sera appelé. Et pourpush_back
A (int x_arg)
est appelé en premier etmove A (A &&rhs)
est appelé ensuite.Bien sûr, le constructeur doit être marqué comme
explicit
, mais pour l'exemple actuel, il est bon de supprimer l'explicitness.production:
la source
emplace_back
vspush_back
.v.emplace_back(x);
où x est explicitement constructible par déplacement mais uniquement explicitement constructible par copie. Le fait que ceemplace_back
soit "implicitement" explicite me fait penser que ma fonction go-to pour l'ajout devrait probablement l'êtrepush_back
. Pensées?a.emplace_back
deuxième fois, le constructeur de déplacement sera appelé!Un joli code pour les push_back et emplace_back est montré ici.
http://en.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.
la source
emplace_back
l'implémentation conforme transmettra les arguments auvector<Object>::value_type
constructeur lorsqu'il sera ajouté au vecteur. Je me souviens que Visual Studio ne prenait pas en charge les modèles variadic, mais avec les modèles variadic seront pris en charge dans Visual Studio 2013 RC, donc je suppose qu'une signature conforme sera ajoutée.Avec
emplace_back
, si vous transférez les arguments directement auvector<Object>::value_type
constructeur, vous n'avez pas besoin qu'un type soit mobile ou copiable pour laemplace_back
fonction, à proprement parler. Dans levector<NonCopyableNonMovableObject>
cas, cela n'est pas utile, car il avector<Object>::value_type
besoin d'un type copiable ou mobile pour se développer.Mais notez que cela pourrait être utile car
std::map<Key, NonCopyableNonMovableObject>
, une fois que vous allouez une entrée dans la carte, elle n'a plus besoin d'être déplacée ou copiée, contrairement àvector
, ce qui signifie que vous pouvez utiliserstd::map
efficacement avec un type mappé qui n'est ni copiable ni mobile.la source
Un de plus en cas de listes:
la source
Cas d'utilisation spécifique pour
emplace_back
: Si vous devez créer un objet temporaire qui sera ensuite poussé dans un conteneur, utilisez à laemplace_back
place depush_back
. Il créera l'objet en place dans le conteneur.Remarques:
push_back
dans le cas ci-dessus va créer un objet temporaire et le déplacer dans le conteneur. Cependant, la construction sur place utiliséeemplace_back
serait plus performante que la construction puis le déplacement de l'objet (ce qui implique généralement une copie).emplace_back
au lieu depush_back
dans tous les cas sans trop de problème. (Voir exceptions )la source