插入std :: map的最佳方法

时间:2014-08-20 08:59:25

标签: c++ stl stdmap c++03

拥有:

std::map<const std::string,A > cache;

如何插入此容器(可以重复尝试):

cache.insert(std::make_pair(id,ps));

cache.insert(std::pair<std::string,A>(id,ps));

if(cache.find(id) == cache.end()){
 cache[id] = ps;
}

为什么??(就时间和记忆而言)

你有更好的解决方案吗?

更新: 我没有使用C ++ 11

更新-2: 好的,到目前为止我们意识到:

make_pairpair<>类似。

insert[ ](有或没有if检查)都会调用copy。那么......之间的竞争是:

  1. insert
  2. [ ](具有if检查)
  3. [ ]if检查并swap
  4. 你更喜欢哪一个?

    再次感谢

3 个答案:

答案 0 :(得分:6)

我建议emplace

template< class... Args >
std::pair<iterator,bool> emplace( Args&&... args );

// usage:
cache.emplace(id, ps);

但是,这取决于你是否想要第二次插入

  • 失败(如上所述,返回std::pair<iterator,bool>,其中.second表示插入成功或失败 - 如果您不在乎,可以忽略它,作为失败的唯一原因是现有密钥)或

  • 覆盖现有值(最简单且通常完全足以编写cache[id] = ps;,但如果要避免构造元素对的默认构造,则可以使用find然后根据需要覆盖现有或emplace新元素。

有时您可能会考虑将一个或两个参数标记为可移动的(即,您不关心emplace返回后局部变量留在哪个(有效)状态,这可能允许额外的优化)。您可以从上面的原型中看到,使用&&接受了参数,这暗示了执行此类优化的能力。

cache.emplace(std::move(id), std::move(ps));

答案 1 :(得分:5)

第三个在时间上明显较差,因为它在实际插入时要求地图中的两个查找(一个用于find(),一个用于[])。所以坚持使用insert()函数。

现在的问题是:std::make_pair()std::pair<A, B>()?遵循DRY的原则通常是个好主意,这意味着您不应该重复这些类型,因此请使用std::make_pair()

如果你有C ++ 11,最好的选择是使用emplace()

cache.emplace(id, ps);

作为旁注,将地图键入std::map<const std::string, A>毫无意义。地图中的键已经不可变;它只是使用std::map<std::string, A>更简洁(并且不会产生WTF时刻),而且你很难找到这两者不同的情况。

答案 2 :(得分:4)

cache.insert(std::make_pair(id,ps));

这将复制idps。如果他们有“重型”拷贝构造器,这将浪费一些时间和内存。

cache.insert(std::pair<std::string,A>(id,ps));

它确实类似于make_pair

if(cache.find(id) == cache.end()){
 cache[id] = ps;
}

最好不经检查使用:cache[id] = ps;。但是,在第一个元素插入时,将构造类型为decltype(ps)的“默认”对象。然后,将其分配(使用operator=)到ps。如果它很重,这也可能是个问题。但是,如果 swap 方法不可用,我认为它是首选方式。

cache.emplace(id, ps);

这可能看起来像零拷贝安置,但事实并非如此。 emplace接收构造函数参数,因此将调用默认的复制构造函数。它的C ++ 11。

我认为最有效的方法是

cache[id].swap(ps);

这应该是最少量的副本,但缺点是您的ps将被重置(或包含旧值)。