std::map emplace sans copier la valeur
Le C++11 std::map<K,V>
type a un emplace
fonction, comme dans beaucoup d'autres conteneurs.
std::map<int,std::string> m;
std::string val {"hello"};
m.emplace(1, val);
Ce code fonctionne comme annoncé, emplacing la std::pair<K,V>
directement, cependant, il en résulte une copie de key
et val
lieu.
Est-il possible de emplace le type de la valeur directement dans la carte ainsi? Peut-on faire de mieux que de déplacer les arguments dans l'appel à emplace
?
Voici un plus approfondie exemple:
struct Foo
{
Foo(double d, string s) {}
Foo(const Foo&) = delete;
Foo(Foo&&) = delete;
}
map<int,Foo> m;
m.emplace(1, 2.3, string("hello")); //invalid
- J'ai lu un tas de documents et d'en venir à la conclusion qu'il n'est pas possible. Cependant, je ne suis pas le plus expérimenté, développeur C++, donc envie de courir il passé certains gourous ici, dans l'espoir que je me trompe. Pouvez-vous aider?
- ok, lecture de en.cppreference.com/w/cpp/container/map/emplace
- Voulez-vous dire une copie supplémentaire?
val
est une lvalue, par conséquent, une copie devra être fait à un certain point. - imaginez la valeur a d'autres plus complexes de type et qu'il n'était ni copiable, ni mobiles (et donc, bien sûr, ne peut pas être présenté comme une lvalue, ni déplacés/cast de référence rvalue). Je veux que la valeur des arguments du constructeur directement à une sorte de
emplace
fonction de sorte qu'il est instancié à l'aide de transfert parfait et (probablement) la mise en place de nouvelles à l'intérieur de la carte. - J'ai ajouté un autre exemple.
- Voir en.cppreference.com/w/cpp/container/map/emplace pour un exemple 🙂
- naturellement, j'ai eu RTFM, mais sans savoir ce
piecewise_construct
etforward_as_tuple
faire, ce n'était pas évident qu'ils se sont adressés à mon problème. La lecture de la documentation surpair
que Prétorienne lié à offert la pièce manquante (pun intended). - Si je me souviens bien, le
emplace
fonctionnalité demap
, et de tous les autres unique-conteneurs de clés, est en fait plus lentement que l'insert standard. Pour une raison quelconque, la norme exige (je n'ai pas une citation, mais c'est ce que Scott Meyers a montré lors d'une conférence) que le nouvel objet est alloué et déplacé avant de vérifier que la clé n'existe pas encore. Si il existe déjà, l'objet est détruit à nouveau. Bottomline: sauf si je suis en tort, ne pas utiliser de emplace 🙂 - J'ai retrouvé sur youtube: youtube.com/watch?v=smqT9Io_bKo#t=46m00s
- merci pour le lien. Dans mon cas, la clé est unique sur insérer (emplace) donc je vais garder la solution donnée.
- remarque Importante!
- Comme le constructeur pourrait jeter, il a besoin d'un fort exception de garantie, mais le fait de les insérer de façon régulière, je ne vois pas comment cela pourrait être plus lentement.
- Ce qui rend ce code non valide pour g++5.4 (il essaie d'utiliser le supprimer copyconstructor), mais valable pour les versions ci-dessus ?
Vous devez vous connecter pour publier un commentaire.
Les arguments que vous passez à
map::emplace
obtenir transmis au constructeur demap::value_type
, qui estpair<const Key, Value>
. Ainsi, vous pouvez utiliser le par morceaux de la construction constructeur destd::pair
pour éviter les intermédiaires, les copies et les déplacements.Démonstration en direct
En C++17 cela peut plus facilement être réalisé avec la
try_emplace
méthode.Cet ajout à la bibliothèque standard a été couvert dans papier N4279 et devrait être déjà pris en charge dans Visual Studio 2015, CGC 6.1 et LLVM 3.7 (la libc++ de la bibliothèque).