Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moving an object into a map

Tags:

c++

c++11

The problem with this is that the huge objects will be copied into the maps

Huge huge1(some,args);
Huge huge2(some,args);

std::map<int,Huge> map1;
std::map<Huge,int> map2;

map1.insert({0,huge1});
map2.insert({huge2,0});

how can I guarantee a move? Will this work or is there more to it?

map1.insert({0,std::move(huge1)});
map2.insert({std::move(huge2),0});
like image 861
user2015453 Avatar asked Feb 11 '13 16:02

user2015453


3 Answers

std::map::insert has an overload for R-values:

std::pair<iterator,bool> insert(value_type&&);

Any expression which binds to this overload will invoke R-value constructors. Since std::map<K,V>::value_type is std::pair<const key_type, mapped_type>, and std::pair has a constructor that takes R-values:

template<class U1, class U2> 
pair(U1&& x, U2&& y);

then you are guaranteed that R-value constructors for key_type and mapped_type will be invoked, both in the creation of the pair object, and in the map insertion, as long as you insert the pair using an expression that creates R-values, such as:

map1.insert(std::make_pair(0, Huge());

OR

map1.insert(std::make_pair(0, std::move(huge1));

Of course, all of this is dependent on Huge having a proper R-value constructor:

Huge(Huge&& h)
{
  ...
}


Finally, you can also use std::map::emplace if you simply want to construct a new Huge object as an element in the map.

like image 171
Charles Salvia Avatar answered Oct 23 '22 14:10

Charles Salvia


You could do that (the {0,std::move(huge1)} part). But you could also skip the middleman (assuming you're constructing the objects within the function) like this:

map1.emplace(std::piecewise_construct, 0, std::forward_as_tuple(some, args));
map2.emplace(std::piecewise_construct, std::forward_as_tuple(some, args), 0);

Or, if your function is given the objects, you can still use emplace:

map1.emplace(0, std::move(huge1));
map2.emplace(std::move(huge1), 0);
like image 16
Nicol Bolas Avatar answered Oct 23 '22 16:10

Nicol Bolas


An alternative that avoids both copying and moving would be to use std::map::emplace(). From the linked reference page:

Inserts a new element to the container. The element is constructed in-place, i.e. no copy or move operations are performed. The constructor of the element type (value_type, that is, std::pair) is called with exactly the same arguments as supplied to the function, forwarded with std::forward(args)....

like image 6
hmjd Avatar answered Oct 23 '22 15:10

hmjd