C++遍历multiset时增删元素的输出异常原因咨询
问题分析:multiset遍历中erase/insert导致的异常输出
你的代码核心问题是在调用erase(it)后,迭代器it已经失效,后续对it的解引用(*it)和自增操作都是未定义行为,这直接导致了看似奇怪的输出。以下是针对你的代码和输出的具体拆解:
代码执行的实际过程(基于你的输出)
初始multiset内容:{6,7,8,9,10},迭代器it指向第一个元素6。
- 第一次循环:
- 输出
*it→ 6。 - 执行
ms.erase(it):此时it彻底失效,容器变为{7,8,9,10}。 - 执行
if(*it ==6):这里访问的是已经失效的迭代器,属于未定义行为——在你的运行环境中,内存里残留的旧值刚好是6,所以条件成立,插入4,容器变为{4,7,8,9,10}。 - 循环的
it++:对失效迭代器自增,行为未定义,但实际运行中it指向了7的位置(原7的迭代器仍有效)。
- 输出
- 第二次循环:
- 输出
*it→7。 - 执行
ms.erase(it):it失效,容器变为{4,8,9,10}。 if(*it ==6):此时*it的值是未定义的,条件不成立,无插入操作。it++:失效迭代器自增后,实际指向了4的位置。
- 输出
- 第三次循环:
- 输出
*it→4,这就是你疑惑的输出来源。 - 后续流程类似:每次
erase(it)后it失效,it++巧合地指向了容器的下一个有效元素,最终依次输出8、9、10。
- 输出
为什么会出现这种问题?
std::multiset是基于红黑树实现的有序容器,调用erase(it)时,被删除元素对应的迭代器会失效,但其他元素的迭代器仍然有效。但你没有用erase的返回值(C++11及以后,erase(it)会返回下一个有效的迭代器)更新it,反而继续使用失效的it进行操作,这完全违反了容器迭代器的使用规则。- 未定义行为的结果是不可预测的:你看到的输出只是当前环境下的巧合,换个编译器或运行环境,可能会出现崩溃、乱码或完全不同的输出。
正确的遍历+增删写法
如果需要在遍历multiset时删除元素,应该利用erase的返回值更新迭代器:
#include <bits/stdc++.h> using namespace std; int main(){ multiset<int> ms; ms.insert(6); ms.insert(7); ms.insert(8); ms.insert(9); ms.insert(10); auto it = ms.begin(); while(it != ms.end()){ cout << *it << endl; if(*it ==6){ ms.insert(4); // insert不会使multiset的迭代器失效 it = ms.erase(it); // 用erase的返回值更新为下一个有效迭代器 } else { it = ms.erase(it); } } }
如果仅需删除特定元素而非全部元素,写法如下:
auto it = ms.begin(); while(it != ms.end()){ if(*it == 6){ ms.insert(4); it = ms.erase(it); // 删除后跳转到下一个元素 } else { ++it; // 正常遍历 } }
内容的提问来源于stack exchange,提问作者Naruto Uzumaki
相关产品推荐
相关产品推荐

