如何在C ++ map / unordered_map容器中减少查找分配?

时间:2013-02-23 13:37:35

标签: c++ boost unordered-map

假设我在代码中使用std::unordered_map<std::string, Foo>。它非常方便,但不幸的是,每次我想在此地图中进行查找(find())时,我都必须提出std::string的实例。

例如,我们假设我正在对其他字符串进行标记,并希望在每个令牌上调用find()。这迫使我在查找之前围绕每个标记构造std::string,这需要一个分配器(std::allocator,相当于一个CRT malloc())。这可能比实际查找本身慢。它还与其他线程竞争,因为堆管理需要某种形式的同步。

几年前,我找到了 Boost.intrusive 库;当时它只是一个测试版。有趣的是它有一个名为boost::intrusive::iunordered_set的容器,允许代码使用任何用户提供的类型执行查找。

我将解释它是如何让它工作的:

struct immutable_string
{
    const char *pf, *pl;
    struct equals
    {
        bool operator()(const string& left, immutable_string& right) const
        {
            if (left.length() != right.pl - right.pf)
                return false;

            return std::equals(right.pf, right.pl, left.begin());
        }
    };

    struct hasher
    {
        size_t operator()(const immutable_string& s) const
        {
            return boost::hash_range(s.pf, s.pl);
        }
    };

};

struct string_hasher
{
    size_t operator()(const std::string& s) const
    {
        return boost::hash_range(s.begin(), s.end());
    }
};

std::unordered_map<std::string, Foo, string_hasher> m;
m["abc"] = Foo(123); 

immutable_string token; // token refers to a substring inside some other string

auto it = m.find(token, immutable_string::equals(), immutable_string::hasher());

另一件事是加速&#34;查找和插入,如果没有找到&#34;用例 - lower_bound()的技巧仅适用于有序容器。侵入式容器具有名为insert_check()insert_commit()的方法,但我认为这是一个单独的主题。

2 个答案:

答案 0 :(得分:1)

说到lexing,我个人使用两个简单的技巧:

  1. 我使用StringRef(类似于LLVM),只包装char const*size_t并提供类似字符串的操作(显然只有const操作)
  2. 我使用bump分配器(使用4K的块)
  3. 来汇集遇到的字符串

    这两个组合非常有效,但需要了解的是,一旦池被销毁,指向池中的所有StringRef显然都会失效。

答案 1 :(得分:1)

结果boost::unordered_map(自1.42开始)有一个find重载,需要CompatibleKeyCompatibleHashCompatiblePredicate类型,因此它可以完全执行我问过这里。