Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Emplacing a std::pair

Tags:

c++

c++11

stl

Is there a way of emplacing a std::pair?

std::unordered_map<int, std::pair<std::string, std::string>> my_map;
my_map.emplace(1, "foo", "bar"); // Error

Of course inserting is possible:

my_map[2] = std::make_pair("bar", "foo");

But doesn't this require unnecessary copying/moving?

like image 666
Daniel Avatar asked Sep 10 '14 13:09

Daniel


People also ask

How do you initialize a pair in C++?

Another way to initialize a pair is by using the make_pair() function. g2 = make_pair(1, 'a'); Another valid syntax to declare pair is: g2 = {1, 'a'};

What is std :: pair?

std::pair is a class template that provides a way to store two heterogeneous objects as a single unit. A pair is a specific case of a std::tuple with two elements.

Is std :: pair a container?

std::pair is not a Container.

What does emplace return C++?

It returns a bool pair that will indicate if the insertion is occurred or not and returns an iterator pointing to the newly inserted element.


3 Answers

Is there a way of emplacing a std::pair?

The arguments need to be suitable for a constructor of pair<int, pair<string,string>>, the map's value_type:

my_map.emplace(1, std::make_pair("foo", "bar")); 

But doesn't this require unnecessary copying/moving?

No; make_pair makes a pair of pointers to the string literals, which are then used to initialise (in the case of emplace) or assigned to (in the case of []) the strings contained in the map.

like image 151
Mike Seymour Avatar answered Oct 12 '22 10:10

Mike Seymour


In this case there is little point in emplacing the parts of the "value-type" std::pair, as std::string can both be efficiently converted from a C-string, and can be efficiently moved into the map. Simple m.emplace( 3, std::make_pair( "bob", "alice" ) ) and you are 99% of the way to optimal efficiency.

However, if you have a std::map that maps to a type that cannot be efficiently constructed that way, C++11 provides std::piecewise_construct for std::pair to be emplaced.

struct A { }; // nothing struct C { C(C&&)=delete; }; // no copy/move struct B { B()=delete; B(B&&)=delete; B(C&&, C&&) {}; }; // no copy/move, only annoying ctor  std::map< int, std::pair<A,B> > test; // test.emplace( 0, std::make_pair( A{}, B{} ); // does not compile // test.emplace( 0, std::make_pair( A{}, B{C{},C{}} ); // does not compile test.emplace( std::piecewise_construct,   std::make_tuple(0),   std::forward_as_tuple(     std::piecewise_construct,     std::forward_as_tuple(A{}),     std::forward_as_tuple( C{}, C{} )   ) ); // compiles! 

live example

This is an extreme corner case, as efficient-move objects are far more common.

like image 33
Yakk - Adam Nevraumont Avatar answered Oct 12 '22 09:10

Yakk - Adam Nevraumont


Yes there is:

my_map.emplace(1, std::make_pair("foo", "bar"));
like image 39
101010 Avatar answered Oct 12 '22 10:10

101010