C++ std::unordered_map 仅在新元素不存在时插入新元素的最快方法

use*_*112 2 c++ performance c++20

我有一个unordered_map存储大对象:

std::unordered_map<uint64_t, LargeObject> map;

LargeObject 是一个 POD 数组/没有指针成员。

我收到了很多LargeObjects,所以我只想在它们不存在的情况下将它们插入到地图中(很多时候它们确实存在,因为我正在收听多个来源)。

性能很重要,因为我收到了数百万美元。

似乎有几种方法可以做到这一点:

map[key] = largeObject;
Run Code Online (Sandbox Code Playgroud)

或者:

map.insert(std::make_pair<uint64_t, LargeObject>(key, largeObject);
Run Code Online (Sandbox Code Playgroud)

或者:

if(map.count(key) == 0)
{
    map[key] = largeObject;
}
Run Code Online (Sandbox Code Playgroud)

或者:

auto iter = map.find(key);
if(iter == map.end())
{
    map[key] = largeObject;
}
Run Code Online (Sandbox Code Playgroud)

也许还有更多我没有包括在内。

当地图的值是一个大对象时,哪种插入技术最有效?

Bar*_*rry 7

try_emplace就是为了。API 的设置方式是避免构建节点,甚至是值,除非绝对必要。它来自N4279

在你的情况下,那将是:

auto [it, success] = map.try_emplace(key, largeObject);
Run Code Online (Sandbox Code Playgroud)

OP 中的四个选项中的每一个都有问题:

  • map[key] = largeObject实际上并没有做你所要求的,它会覆盖现有的项目。即使它不存在,它也需要默认构造和复制分配。

  • withcountfindboth的方法需要两次查找。

  • map.insert(std::make_pair<uint64_t, LargeObject>(key, largeObject)); 是单次查找,但需要无条件地构造大对象和对。

OP 中没有提到的是另一种选择:map.emplace(key, largeObject);这有一个问题,pair即在key存在的情况下是否创建了实际上并没有指定。它适用于某些实现。其动机try_emplace是正确指定 API,以便在已经存在的情况下pair 绝对不会被创建key