提示错误时的emplace_hint性能

时间:2018-06-04 18:20:51

标签: c++ multimap

我正在尝试确定是否应使用emplace_hint将密钥插入multimap(与常规emplace相对)。我已经在之前的操作中(在同一个键上)计算了键的范围:

range = multimap.equal_range(key); 

我应该使用range.firstrange.second,还是没有任何内容作为插入键值对的提示?如果范围是空的怎么办?

2 个答案:

答案 0 :(得分:10)

  

我应该使用range.first,range.second或者什么都不作为提示来插入键值对吗?

正如std::multimap::emplace_hint()所述:

  

在容器中插入一个新元素,尽可能靠近之前的位置提示。

(重点是我的)你应该使用范围内的second迭代器,它应该使插入更有效:

  

复杂性

     

一般来说,容器的大小是对数的,但如果在提示之前插入新元素,则摊销常数。

对于空范围,使用second迭代器仍然可以,因为它应该总是指向大于元素或者在最后一个后面,如果不存在这样的话。

答案 1 :(得分:1)

首先,表现明智,如果您使用range.firstrange.second,则不会有任何区别。让我们看一下equal_range的返回值:

  

std::equal_range - 返回值

     

std::pair包含一对定义所需范围的迭代器,   第一个指向第一个不小于value的元素   第二个指向第一个元素大于值。如果   没有不小于value的元素,last返回为   第一要素。同样,如果没有大于值的元素,   last作为第二个元素返回

这意味着 - 当获得值key时,range.firstrange.secod都是represent positions wheremay be correctly inserted right before. So performance wise it should not matter if you use range.first or range.last`。复杂性应该是"摊销常数",因为新元素是在提示之前插入的。

其次,当范围是"空"时,range.firstrange.second都是一个接一个的,因此性能和结果是相同的,实际上就像你在没有任何提示的情况下使用emplace一样。

请参阅以下程序演示:

int main()
{
    std::multimap<std::string, std::string> m;

    // some clutter:
    m.emplace(std::make_pair(std::string("k"), std::string("1")));
    m.emplace(std::make_pair(std::string("k"), std::string("2")));
    m.emplace(std::make_pair(std::string("z"), std::string("1")));
    m.emplace(std::make_pair(std::string("z"), std::string("2")));

    // relevant portion of demo data: order a-c-b may be preserved
    m.emplace(std::make_pair(std::string("x"), std::string("a")));
    m.emplace(std::make_pair(std::string("x"), std::string("c")));
    m.emplace(std::make_pair(std::string("x"), std::string("b")));


    auto r = m.equal_range("x");
    // will insert "x.zzzz" before "x.a":
    m.emplace_hint(r.first, std::make_pair(std::string("x"), std::string("zzzz")));

    // will insert "x.0" right after "x.b":
    m.emplace_hint(r.second, std::make_pair(std::string("x"), std::string("0")));

    auto rEmpty = m.equal_range("e");
    // "empty" range, normal lookup:
    m.emplace_hint(rEmpty.first, std::make_pair(std::string("e"), std::string("b")));
    m.emplace_hint(rEmpty.second, std::make_pair(std::string("e"), std::string("a")));

    auto rWrong = m.equal_range("k");
    m.emplace_hint(rWrong.first, std::make_pair(std::string("z"), std::string("a")));

    for (const auto &p : m) {
        std::cout << p.first << " => " << p.second << '\n';
    }
}

输出:

e => b
e => a
k => 1
k => 2
x => zzzz
x => a
x => c
x => b
x => 0
z => a
z => 1
z => 2

简而言之:如果预先计算出range有效key,则在插入key时使用它。无论如何它会有所帮助。

编辑:

关于是否&#34;无效&#34;提示可能会导致插入一个不会反映插入顺序的位置&#34;对于具有相同键的值。这可以从一般的多图表语句得出结论&#34;其键比较等效的键值对的顺序是插入的顺序,并且不会改变。 (自C ++ 11起)&#34;。

我没有在任何规范性文件中找到对一种或另一种观点的支持。我刚刚在cplusplus multimap / emplace_hint文档中找到以下语句:

emplate <class... Args>
  iterator emplace_hint (const_iterator position, Args&&... args);
     

位置提示可以插入元素的位置。如果位置指向,则该函数优化其插入时间   将跟随插入元素的元素(如果是,则为结尾)   将是最后一次)。请注意,这不会强制新元素   位于multimap容器中的那个位置(a。中的元素)   multimap始终遵循特定的顺序)。 const_iterator是一个成员   type,定义为指向的双向迭代器类型   元件。

我知道这不是一个规范性参考,但至少我的Apple LLVM 8.0编译器遵循这个定义(参见上面的演示): 如果一个元素插入一个&#34;错误的&#34;提示,即一个指向甚至在插入一对的位置之前,算法识别并选择一个有效位置(参见插入&#34; z&#34; =&gt;&#34; a&#34;其中一个提示指向&#34; x&#34; -element)。 如果我们使用键的范围&#34; x&#34;并使用range.first,将第一个x之前的位置解释为有效位置。

所以:我认为m.emplace_hint(r.first,...的行为方式是算法立即选择一个有效的位置,to a position close to hint否决了一般语句&#34;键值对的顺序密钥比较等效是插入的顺序,不会改变。 (自C ++ 11起)&#34;。