C++ std::map insert()提示位置:c和#x2B+;98和c++;11

C++ std::map insert()提示位置:c和#x2B+;98和c++;11,c++,c++11,dictionary,insert,C++,C++11,Dictionary,Insert,在我读到有关位置的信息时,可以为函数添加一个提示,即对于c++98,“如果position指向将位于插入元素之前的元素,则函数会优化其插入时间”,而对于c++11,则会进行优化“如果位置指向将跟随插入元素的元素(如果是最后一个元素,则指向末尾)” 这是否意味着在切换到符合C++11的编译器时,以下形式的代码片段(我正在处理的遗留代码中有大量代码,并以“有效STL”第24项为模型)的性能受到影响 auto pLoc = someMap.lower_bound(someKey); if(pLoc !

在我读到有关位置的信息时,可以为函数添加一个提示,即对于c++98,“如果
position
指向将位于插入元素之前的元素,则函数会优化其插入时间”,而对于c++11,则会进行优化“如果
位置
指向将跟随插入元素的元素(如果是最后一个元素,则指向末尾)”

这是否意味着在切换到符合C++11的编译器时,以下形式的代码片段(我正在处理的遗留代码中有大量代码,并以“有效STL”第24项为模型)的性能受到影响

auto pLoc = someMap.lower_bound(someKey);
if(pLoc != someMap.end() && !(someMap.key_comp()(someKey, pLoc->first)))
    return pLoc->second;
else
    auto newValue = expensiveCalculation();
    someMap.insert(pLoc, make_pair(someKey, newValue));  // using the lower bound as hint
    return newValue;

对于C++11,改进此模式的最佳方法是什么?

是的,它会影响复杂性。给出正确的提示将使
插入()
具有摊销常数复杂性,而给出错误提示将迫使贴图从一开始就搜索位置,给出对数复杂性。基本上,一个好的提示会使插入在常数时间内发生,无论您的贴图有多大;如果提示不好,则在较大的贴图上插入速度会较慢


显然,解决方案是用
上限
搜索提示,而不是
下限

C++98规范是标准中的一个缺陷。请参阅和中的讨论

回想一下,
lower\u-bound
将迭代器返回给键不小于指定键的第一个元素,而
upper\u-bound
将迭代器返回给键大于指定键的第一个元素。如果容器中没有与指定键等效的键,则
lower\u-bound
upper_-bound
返回相同的内容-如果元素在映射中,则返回位于键后面的元素的迭代器


因此,换句话说,您当前的代码在C++11规范下已经正常工作,而事实上在C++98有缺陷的规范下是错误的。

我认为正确的C++11样式提示插入可能如下所示:

iterator it = table.upper_bound(key);   //upper_bound returns an iterator pointing to the first element that is greater than key
if (it == table.begin() || (--it)->first < key) {
    // key not found path
    table.insert(it, make_pair(key, value));
}
else {
    // key found path
    it->second = value;
}
iterator it=table.upper_-bound(key);//upper_-bound返回指向大于key的第一个元素的迭代器
if(it==table.begin()||(-it)->first秒=值;
}

工作lambda函数的快照,供您参考。 注意:
m_map
不应为空。如果map为空,则不知道在何处添加元素

    auto create_or_get_iter = [this] (const K& key) {

        auto it_upper = m_map.upper_bound(key);
        auto it_effective = it_upper == m_map.begin() ? it_upper : std::prev(it_upper);
        auto init_val = it_effective->second;

        if (it_effective == m_map.begin() || it_effective->first < key) {
            return m_map.insert(it_effective, std::make_pair(key, init_val));
        } else {
            it_effective->second = init_val;
            return it_effective;
        }

    };
auto-create\u或\u-get\u iter=[this](const K&key){
自动it_上限=m_映射。上限(键);
auto it_effective=it_upper==m_map.begin()?it_upper:std::prev(it_upper);
自动初始化值=有效->秒;
if(it_effective==m_map.begin()| | it_effective->first秒=初始值;
将其返回至有效状态;
}
};

这是一个奇妙的不兼容性。很棒的工作,C++。看,我不确定是否有任何实现实际上实现了C++ 98的规范。@ LealNeSraceSein轨道:那么,你是否喜欢与C++ 98的bug兼容的bug,就像Windows API的葡萄酒承诺一样?indows,Wine中也发现了同样的漏洞,这当然是同一API规范的一个完全不同的实现。这有点令人印象深刻,但我宁愿ISO修复C++98中的缺陷,而不是将其传播到永恒。@ArneVogel:我在一定程度上同意你的观点,但这一特定的更改潜入doe的方式这似乎不可接受。它不仅悄然破坏了早期的程序,而且它也是一个非常微妙的变化,我怀疑很多人甚至不会注意到。它似乎与C++项目的声明目标大不相同,这是一个上升趋势。不过请不要误解我:“我没有更好的建议。”“早期程序”是根据C++98规范编写的?因为这需要使用,比如说,
lower_bound
,然后在检查返回的迭代器是否为
begin()之后,对其进行递减
因为如果不是这样的话,它将是UB。回答得很好!我只想补充一点,在
end()时,旧规范不允许在已知新密钥小于任何现有密钥(即在前面插入)时提供提示
对任何事情都没有用处。通过修复,提示迭代器的工作原理与传递到序列容器的
insert()
的迭代器相同,这解决了这个问题。@ArneVogel Yep,这在N1780的开头提到过。如果
为空,这将崩溃。如果
m\u map
为空,这将崩溃。