【问题标题】:When do you use std::unordered_map::emplace_hint?你什么时候使用 std::unordered_map::emplace_hint?
【发布时间】:2014-05-13 02:01:13
【问题描述】:

我知道如何使用std::unordered_map::emplace,但是如何使用emplace_hintcpluspluscppreference 都没有提供一组示例来说明我们如何知道将元素放在哪里。

谁能提供一些关于这方面的信息或给出一些示例/说明我们何时可能知道放置的元素应该去哪里?

【问题讨论】:

    标签: c++ c++11 stl unordered-map


    【解决方案1】:

    unordered_map 可能对提示有什么作用?好吧,如果迭代器使用与 emplace_hint 被要求插入的元素相同的键来寻址元素,那么它可能会很快失败 - 只是一个键比较,没有任何散列或在任何散列冲突元素列表中摸索桶。但是,如果键不匹配,则提示在其他方面是无用的,因为任何其他键 - 无论值多么“接近” - 应该(概率上)位于完全不相关的存储桶中(考虑到通常被认为是“好”的散列函数),所以时间会浪费在关键比较上,只能像普通的emplace一样重新开始。

    当您插入预先按键排序的元素时,这可能很有用,旨在删除过程中的大量重复项,但是键太大了,将迭代器保留到刚刚插入的元素比密钥的副本,或者哈希函数可能特别慢。

    unordered_map::emplace_hint 的另一个好处是与 map::emplace_hint 更好的 API 兼容性,因此代码可以切换容器类型并让 emplace_hints 不会中断编译,尽管它们最终可能比代码切换到更慢emplace() 作为对 map 有帮助的关闭但不同的键提示可能对 unordered_map 无用。


    只需获取 GCC 10.2 g++ -E 的输出,看看它是否执行上述操作。 emplace_hint 调用_M_insert_multi_node(...) 其中有这行:

    __node_base* __prev = __builtin_expect(__hint != nullptr, false)
                          && this->_M_equals(__k, __code, __hint)
                          ? __hint
                          : _M_find_before_node(__bkt, __k, __code);
    

    上面,__k是可以插入的key,__code是哈希码,__hint是提示迭代器/指针; _M_equals(...) 返回:

    return _Equal_hash_code<__node_type>::_S_equals(__c, *__n) &&
           _M_eq()(__k, this->_M_extract()(__n->_M_v()));
    

    因此,在使用提示迭代器。这是它使用提示的唯一情况。想象一下,在逻辑上,存储桶有一些碰撞元素与键 K1、K2、K3、K4 链接在一起,并且您的提示迭代器指向 K4,但您尝试使用 K2 插入重复项:因为迭代器仅向前 em>,您必须使用_M_find_before_node(...) 才能比提示指向的更早到达链中的碰撞元素。在_M_find_before_node(...) 之后,您可以从 K1 向前扫描,以查看要插入的键 - K2 - 是否已经存在于在桶中碰撞的元素中。

    (当已知键比较很便宜时,可以通过跳过哈希比较来改进实现,但是使用类型特征来正确处理该条件会有点痛苦 - 你怎么知道哪些键相等函数很便宜? 对于小型、标准布局、可简单复制的类型或类似类型,至少可以假设无序容器使用默认的std::equals&lt;&gt; 比较来实例化......)。

    【讨论】:

    • 我没有完全得到这个答案。也许是因为它的措辞。所以除非我预先订购了多个钥匙,否则它是没用的?
    • @Dean:您不一定必须拥有“预先订购的多个键”-它们自然发生的顺序可能意味着重复键具有足够高的连续发生概率使迭代器保持最后放置的值是值得的,因为您可以快速拒绝重复项。尽管如此,这一切都基于我能想到的唯一可能使用的提示——如果你的实现实际上没有使用提示,那么你就是在浪费时间和精力来提供它。
    • 如果有一个函数可以将迭代器返回到元素(如果找到)或有效提示(如果未找到),这可能会很有用 - 类似于您如何使用 lower_bound搜索或生成map 的提示。
    • @user253751: 已经有 insert_or_assigntry_emplace 用于查找尝试之后会立即插入或更新,但是是的 - 有一些东西可以帮助您及时将两者分开可能会很好有时:最有用的事情是保留桶号并使用它来避免散列;你不能有一个特定存储桶的迭代器,并且一些存储桶缺少元素 - 所以迭代器提示很尴尬。
    • unordered_map 从排序的源(例如文件)填充时,我想知道整数键。我认为在这种情况下emplace_hint 没有任何优势,但我希望我错了。
    猜你喜欢
    • 1970-01-01
    • 2011-09-04
    • 1970-01-01
    • 2010-11-16
    • 2010-09-19
    • 2012-04-23
    • 2018-01-17
    • 1970-01-01
    相关资源
    最近更新 更多