std::map 擦除 - 将迭代器传递给错误的地图

std::map erase - pass iterator to wrong map

拿这个 C++ 片段来说:

#include <map>

int main() {
    std::map<int, int> m1;
    m1[1] = 2;

    std::map<int, int> m2;
    m2[3] = 4;
    m1.erase(m2.begin());

    return m2.size();
}

关于神箭:https://godbolt.org/z/mJBszn

感觉这一定是未定义的行为。那是对的吗?如果是这样,标准的哪一部分是这样说的?

这都是参考 C++17。

编辑 2** 我收回我最初所说的话,我只是通过部分 c++ 标准和评论。在 §26.2.6 中,关联容器上下文中 a.erase(r) 的标准状态是 "If no such element exists, returns a.end()." 但是,该标准还声明 "r denotes a valid dereferenceable iterator to a"

由于 m2.begin() 不是这种情况,这不符合标准,因此是未定义的行为。

This feels like it must be undefined behaviour. Is that correct?

是的。

If so, which part of the standard says so?

标准在 [associative.reqmts] 注释 8 中消除了这一点愚蠢。我是 citing n4659 因为这是我的 link 接近 C++17。目前 C++20 仍然是一个移动目标。

深入 [tab:container.assoc.req] 我们发现三个 erase 采用迭代器的重载,

a.erase(q)
a.erase(r)
a.erase(q1, q2)

其中 a.erase(r) 是提问者感兴趣的。

table 仅说明程序运行时会发生什么;但是 table 的序言指出

q denotes a valid dereferenceable constant iterator to a, r denotes a valid dereferenceable iterator to a, [q1, q2) denotes a valid range of constant iterators in a

也就是说,如果迭代器r不是来自mapaaend迭代器,或者已经失效或者否则会变得不可引用,合同就被打破,结果也没有定义。

我包括 qq1q2 以表明规则对于常量迭代器和迭代器范围是相同的。