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

std::map erase - pass iterator to wrong map

本文关键字:错误 映射 迭代器 map 擦除 std      更新时间:2023-10-16

拿这个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

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

这感觉它一定是未定义的行为。这是对的吗?

是的。

如果是这样,标准的哪一部分是这样说的?

该标准在[associaciative.reqmts]注释8中打下了这种愚蠢之处。我引用 n4659 是因为这是我链接到并接近 C++17 的内容。此时,C++20仍然是一个移动目标。

深入研究[tab:container.assoc.req],我们发现三个erase重载需要迭代器,

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

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

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

q表示a的有效可取消引用常量迭代器,r表示a的有效可取消引用迭代器,[q1q2(表示a常量迭代器的有效范围

换句话说,如果迭代器r不是来自mapaaend迭代器,或者已被无效或以其他方式被渲染为不可取消引用,则合约被破坏,结果未定义。

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

这都是参考C++17。

编辑 2** 我收回了我最初所说的内容,我只是从 c++ 标准的一部分和评论中穿行。在 §26.2.6 中,a.erase(r( 在关联容器上下文中的标准状态是"如果不存在这样的元素,则返回 a.end((。但是,该标准还指出"r 表示对 a 的有效可取消引用迭代器">

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