70

The C++11 std::map<K,V> type has an emplace function, as do many other containers.

std::map<int,std::string> m; std::string val {"hello"}; m.emplace(1, val); 

This code works as advertised, emplacing the std::pair<K,V> directly, however it results in a copy of key and val taking place.

Is it possible to emplace the value type directly into the map as well? Can we do better than moving the arguments in the call to emplace?


Here's a more thorough example:

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 
14
  • @Cheersandhth.-Alf, I've read a bunch of documents and come to the conclusion that it's not possible. However I am not the most experienced C++ developer so wanted to run it past some of the gurus here, in the hope that I am wrong. Can you help? Commented Jan 15, 2015 at 9:41
  • 5
    Do you mean an extra copy? val is an lvalue, so a copy will have to be made at some point. Commented Jan 15, 2015 at 9:42
  • 2
    @juanchopanza, imagine the value was some more complex type and that it was neither copyable nor moveable (and so of course cannot be introduced as an lvalue, nor moved/cast to an rvalue reference). I want to provide the value's constructor arguments directly to some kind of emplace function so that it is instantiated using perfect forwarding and (presumably) placement new within the map. Commented Jan 15, 2015 at 9:45
  • 1
    I found it again on youtube: youtube.com/watch?v=smqT9Io_bKo#t=46m00s Commented Jan 15, 2015 at 12:39
  • 4
    Important note! Commented Jan 15, 2015 at 15:06

2 Answers 2

88

The arguments you pass to map::emplace get forwarded to the constructor of map::value_type, which is pair<const Key, Value>. So you can use the piecewise construction constructor of std::pair to avoid intermediate copies and moves.

std::map<int, Foo> m; m.emplace(std::piecewise_construct, std::forward_as_tuple(1), std::forward_as_tuple(2.3, "hello")); 

Live demo

Sign up to request clarification or add additional context in comments.

2 Comments

This is very ugly, but you take what you get :)
Just adding that in order to compile this you should add #include <tuple>
39

In C++17 this can more easily be achieved with the try_emplace method.

map<int,Foo> m; m.try_emplace(1, 2.3, "hello"); 

This addition to the standard library was covered in paper N4279 and should already be supported in Visual Studio 2015, GCC 6.1 and LLVM 3.7 (the libc++ library).

2 Comments

Yes, try_emplace() is really the best solution. In particular, emplace() always constructs a Key-Value pair on the heap. So, if the Key is actually found in the table, emplace() will delete that just newly constructed Key-Value pair again. try_emplace on the contrary does everything in the expected order: Check, if they Key exists, and if yes, return an iterator to that Key-Value pair. If not, then it emplaces the new Key and Value into the container.
Well, simple .emplace() is the only option if the key has to be constructed in-place, and has no drawback if you know it is not yet present in the map.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.