【问题标题】:Why is map::operator[] slow by design?为什么 map::operator[] 设计缓慢?
【发布时间】:2013-11-05 10:00:44
【问题描述】:

问题:

人们对此抱怨: In STL maps, is it better to use map::insert than []?

访问时

std::map<Key, ExpensiveDefaultConstructorValue> data;
data[key1] // <-- Calls default constructor each time it is called, 
           // even when the element is there

实现简单而优雅,但完全低效(嗯,取自 unordered_map)。

_Tp& operator[](const key_type& __key)
   { return _M_ht.find_or_insert(value_type(__key, _Tp())).second; }

显而易见的解决方案

_Tp& operator[](const key_type& __key)
   { return _M_ht.find_or_insert_default(key_type(__key)).second; }

find_or_insert_default 仅在需要时才调用_Tp()(即元素不存在)

为什么不呢?

在知道自己需要新元素之前,这种悲观的做法是否可能导致其他问题?

这是标准库,他们应该不遗余力地对其进行优化。为什么不使用这种简单的方法?

【问题讨论】:

  • 你确定他的规范需要这个吗?符合标准的实现会更高效吗?
  • 嗯,这就是我要问的。代码示例来自 gcc 的 libstdc++
  • 一个天真的假设可能是编写该代码的人没有考虑到默认 ctor 可能会产生不小的成本的可能性。
  • 您提出的建议已完成(取决于编译器版本)。但是它没有解决data[non_existing_key] = some_new_value 的问题,它需要创建默认值以便可以分配给它。

标签: c++ performance stl std libstdc++


【解决方案1】:

至少从g++ 4.5 开始,std::map 就没有出现过这样的问题:

// stripped comments and requirements
mapped_type&
operator[](const key_type& __k)
{    
    iterator __i = lower_bound(__k);

    if (__i == end() || key_comp()(__k, (*__i).first))
        __i = insert(__i, value_type(__k, mapped_type()));
    return (*__i).second;
}

您发布的 sn-p 不是来自 std::map,而是来自 hash_map,这是一个 GCC extension 到库:

00052 /** @file backward/hash_map
00053  *  This file is a GNU extension to the Standard C++ Library (possibly
00054  *  containing extensions from the HP/SGI STL subset).
00055  */

由于它是一个扩展,因此维护者并没有义务遵循任何复杂性/性能规则(即使您提出的功能会更快)。请注意,hash_map 已替换为 std::unordered_map 的实现,如果元素存在,则不使用构造函数。

【讨论】:

    猜你喜欢
    • 2015-12-11
    • 2016-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多