repousser vs emplace dos
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 surcharge push_back
prenant une valeur de référence Je ne vois pas tout à fait quel est le but de emplace_back
devient?
6 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 utile: void emplace_back(Args&&...)
;
au lieu de prendre un value_type
il prend une liste variadique d'arguments, de sorte que cela signifie que vous pouvez maintenant parfaitement en avant les arguments et construire directement un objet dans un contenant sans que temporaire.
c'est utile parce que peu importe combien d'intelligence RVO et move sémantic apportent à la table il y a encore des cas compliqués où un push_back est susceptible de faire des copies (ou move) inutiles. Par exemple, avec la traditionnelle insert()
la fonction d'un std::map
, vous devez créer un temporaire, qui sera ensuite copié dans un std::pair<Key, Value>
, qui sera ensuite copié dans la carte:
std::map<int, Complicated> m;
int anInt = 4;
double aDouble = 5.0;
std::string aString = "C++";
// cross your finger so that the optimizer is really good
m.insert(std::make_pair(4, Complicated(anInt, aDouble, aString)));
// should be easier for the optimizer
m.emplace(4, anInt, aDouble, aString);
alors pourquoi n'ont-ils pas implémenté la bonne version d'emplace_back dans MSVC? En fait, il m'a mis sur écoute aussi il y a un moment, donc j'ai posé la même question sur le Visual C++ blog . 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: sont bêta 2 fonctions emplace juste une sorte de placeholder droit maintenant?
A: comme vous le savez peut-être, modèles variadiques ne sont pas implémentés dans VC10. Nous simuler avec préprocesseur machines pour des choses comme
make_shared<T>()
, tuple, et le nouveau les choses dans<functional>
. Ce préprocesseur machines est relativement difficile à utiliser et à entretenir. Également, il affecte de manière significative la compilation vitesse, comme nous devons à plusieurs reprises inclure subheaders. En raison d'un la combinaison de nos contraintes de temps et vitesse de compilation préoccupations, nous Je n'ai pas simulé de modèles variadiques dans nos fonctions emplace.quand les gabarits variadiques sont mis en œuvre dans le compilateur, vous pouvez attendez-vous à ce que nous en profitions dans les bibliothèques, y compris dans nos fonctions emplace. Nous prenons conformité très sérieusement, mais malheureusement, nous ne pouvons pas tout faire tout à la fois.
C'est une décision compréhensible. Tous ceux qui ont essayé juste une fois d'émuler modèle variadique avec préprocesseur trucs horribles sait à quel point ce genre de choses devient dégoûtant.
emplace_back
ne devrait pas prendre un argument de type vector::value_type
, mais plutôt des arguments variadiques qui sont transmis au constructeur de l'élément ajouté.
template <class... Args> void emplace_back(Args&&... args);
Il est possible de passer d'un value_type
, qui sera transmis au constructeur de copie.
parce qu'il transmet les arguments, cela signifie que si vous n'avez pas de valeur, cela signifie encore que le conteneur stockera une copie" copiée", pas une copie déplacée.
std::vector<std::string> vec;
vec.emplace_back(std::string("Hello")); // moves
std::string s;
vec.emplace_back(s); //copies
mais ce qui précède doit être identique à ce que push_back
fait. Il est probablement plutôt destiné à des cas d'utilisation comme:
std::vector<std::pair<std::string, std::string> > vec;
vec.emplace_back(std::string("Hello"), std::string("world"));
// should end up invoking this constructor:
//template<class U, class V> pair(U&& x, V&& y);
//without making any copies of the strings
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)
s'appelle d'abord et move A (A &&rhs)
s'appelle ensuite.
bien sûr, le constructeur doit être marqué comme explicit
, mais pour l'exemple actuel est bon pour supprimer explicitness.
#include <iostream>
#include <vector>
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> a;
std::cout << "call emplace_back:\n";
a.emplace_back (0);
}
{
std::vector<A> 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
conforme mise en œuvre va de l'avant des arguments à l' vector<Object>::value_type
constructeur lorsqu'il est ajouté au vecteur. Je me souviens que Visual Studio n'a pas pris en charge les gabarits variadic, mais avec variadic les gabarits seront pris en charge dans Visual Studio 2013 RC, donc je suppose qu'une signature conforme sera ajoutée.
avec emplace_back
, si vous transmettez les arguments directement au constructeur vector<Object>::value_type
, vous n'avez pas besoin d'un type pour être mobile ou copiable pour emplace_back
fonction, à proprement parler. Dans le cas vector<NonCopyableNonMovableObject>
, cela n'est pas utile, car vector<Object>::value_type
a besoin d'un type copiable ou mobile pour se développer.
mais notez que cela pourrait être utile pour std::map<Key, NonCopyableNonMovableObject>
, car une fois que vous attribuez 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 utiliser std::map
efficacement avec un type cartographié qui n'est ni copiable ni Mobile.
un joli code pour push_back et emplace_back est affiché ici.
http://en.cppreference.com/w/cpp/container/vector/emplace_back
, Vous pouvez voir l'opération de déplacement sur push_back et pas sur emplace_back.