将对象移动到地图中

时间:2013-02-11 16:29:32

标签: c++ c++11

这个问题是巨大的物体将被复制到地图中

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});

我怎样才能保证搬家?这会有用还是有更多呢?

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

4 个答案:

答案 0 :(得分:44)

std::map::insert对R值有重载:

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

任何绑定到此重载的表达式都将调用R值构造函数。由于std::map<K,V>::value_typestd::pair<const key_type, mapped_type>std::pair有一个带R值的构造函数:

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

然后保证key_typemapped_type的R值构造函数将在pair对象的创建和地图插入中被调用,只要您使用创建R值的表达式插入对,例如:

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

OR

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

当然,所有这些都依赖于Huge具有适当的R值构造函数:

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


最后,如果您只想构建一个新的std::map::emplace对象作为地图中的元素,也可以使用Huge

答案 1 :(得分:15)

你可以这样做({0,std::move(huge1)}部分)。但你也可以跳过中间人(假设你正在构建函数中的对象),如下所示:

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

或者,如果为您的函数提供了对象,您仍然可以使用emplace

map1.emplace(0, std::move(huge1));
map2.emplace(std::move(huge1), 0);

答案 2 :(得分:6)

避免复制和移动的替代方法是使用std::map::emplace()。从链接的参考页面:

  

将新元素插入容器。 元素是就地构造的,即不执行复制或移动操作。使用与提供的完全相同的参数调用元素类型(value_type,即std :: pair)的构造函数到函数,转发std :: forward(args)....

答案 3 :(得分:2)

除了上述内容之外,您还可以依赖std::unique_ptr<>缺少复制构造函数,尽管这会稍微改变界面。

#include <iostream>
#include <map>
#include <memory>

class Huge {
 public:
  Huge(int i) : x{i} {}
  int x;
};

using HugePtrT = std::unique_ptr<Huge>;
using MyMapT = std::map<int, HugePtrT>;


int
main() {
  MyMapT myMap;
  myMap[42].reset(new Huge{1});
  std::cout << myMap[42]->x << std::endl;
  myMap[43] = std::move(myMap[42]);
  if (myMap[42])
    std::cout << "42: " << myMap[42]->x << std::endl;
  if (myMap[43])
    std::cout << "43: " << myMap[43]->x << std::endl;
}

产生预期的输出:

1
43: 1

如果省略std::move()调用,程序将无法编译。同样,您可以使用.reset()来指定指针。

这样做的好处是它可以处理没有R值构造函数的类,权重非常轻,内存所有权明确定义,并为您提供类似boost::optional<>的语义。可以认为std::unique_ptr比通过R值构造函数移动的对象更轻,因为R值移动对象需要分配(尽管公平,所有C ++ 11我知道支持返回值优化或复制省略的编译器,即使移动了对象的内容。

std::unique_ptr<>这样工作的原因是因为std::unique_ptr<>没有复制构造函数,它只有一个移动构造函数。