插入标准::地图的最佳方法

best way to insert std::map

本文关键字:最佳 方法 地图 标准 插入      更新时间:2023-10-16

haveving:

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检查和交换(

你更喜欢哪一个?

再次感谢

我建议emplace

template< class... Args >
std::pair<iterator,bool> emplace( Args&&... args );
// usage:
cache.emplace(id, ps);

但是,这有点取决于您是否要第二次插入

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

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

有时,您可能需要考虑将一个或两个参数标记为 movable-from(即,您不在乎局部变量在emplace返回后保留在什么(有效(状态,这可能会允许额外的优化(。 从上面的原型中可以看出,使用&&接受参数,这暗示了执行此类优化的能力。

cache.emplace(std::move(id), std::move(ps));
第三个在

时间方面明显较差,因为它在实际执行插入时需要在映射中进行两次查找(一次用于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时刻(,并且您很难找到这两者不同的情况。

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 。如果它很重,这也可能是问题。但是,我认为如果交换方法不可用,它是首选方式。

cache.emplace(id, ps);

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

我认为最有效的方法是

cache[id].swap(ps);

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