如何有效地将(一些)项目从一个 std::map 移动到另一个?

How to efficiently move (some) items from one std::map to another?

我有两个 std::map<> 对象 ab 并且想从一个对象中移动 (extract + insert) 一些元素(节点)根据某些谓词 p.

映射到另一个
for (auto i = a.begin(); i != a.end(); ++i)
    if (p(*i))
        b.insert(a.extract(i))

此代码在 clang 中出现段错误。我认为问题是 i 在其节点从 a.

中提取后的增量

right/only 是否可以通过使用 post 增量来解决此问题?例如:

for (auto i = a.begin(); i != a.end();)
    if (p(*i))
        b.insert(a.extract(i++))
    else
        ++i;

编辑:我删除了关于 "why this works in gcc?" 的部分,因为我无法在当前设置中重现它。我确信它曾经在某个时间点使用过,但是使用 gcc 9.2.1 我遇到了死锁(而不是段错误)。无论哪种方式,在 extract() 之后递增都不起作用。

I assume the problem is the increment of i after it's node has been extracted from a.

确实如此。提取使提取元素的迭代器无效,i 就是这样的迭代器。通过无效迭代器递增或间接的行为未定义。

Why does this seemingly work in gcc but not in clang?

因为程序的行为是未定义的。

Is the right/only way to fix this with a post-increment?

这是 a 解决此问题的正确方法。这不是一个特别糟糕的方法。如果您不想重复增量,一种方法是使用变量:

for (auto i = a.begin(); i != a.end();) {
    auto current = i++;
    if (p(*current)) {
        // moving is probably unnecessary
        b.insert(a.extract(std::move(current)));
    }
}