forward_list迭代器异常:preb++替换为++preb才正常运行的原因
关于forward_list中erase_after使用preb和preb的差异问题
我用C++的forward_list存储字符串,处理元素时,将代码中的it=flis.erase_after(preb++)改为it=flis.erase_after(++preb)后程序运行正常,但我不理解其中原因。逻辑上preb与it指向的元素存在关联,后续循环应该能修正preb的指向,仅删除目标元素,为何用preb++时程序无法正常运行?
我的代码如下:
#include <forward_list> #include <iostream> #include <string> using std::forward_list; using std::cin; using std::cout; using std::string; int main () { string s1 {"abc"}; string s2 ={"abc_list"},temp_str; forward_list<string> flis; auto preb = flis.before_begin(); while (cin >> temp_str) { preb = flis.insert_after(preb,temp_str); } for (auto &i : flis) { cout << i << endl; } preb = flis.before_begin(); auto it =flis.begin(); int flag=0; while (it != flis.end()) { if ( *it == s1)//compare element { flis.insert_after(preb,s2); it=flis.erase_after(preb++);//the ok code should be it=flis.erase_after(++preb) flag=1; //cout << "22222222"<< endl;//debug } else { preb = it ; ++it; } } //cout << "1111111111" <<endl; //debug if (!flag) { flis.insert_after(preb,s2); } for (auto &i : flis) { cout << i << endl; } return 0; }
问题原因分析
要搞懂这个差异,得先明确forward_list的迭代器特性和erase_after的行为:
forward_list是单向链表,before_begin()返回的是首元素之前的哨兵迭代器,只能往后移动。erase_after(pos)的作用是删除pos迭代器之后紧邻的那个元素,并返回被删除元素的下一个迭代器。
结合你代码里的逻辑,当*it == s1时,执行flis.insert_after(preb,s2)后,链表结构变成:preb 指向的位置 -> s2 -> it指向的s1 -> ...
1. 使用preb++的错误逻辑
preb++是后置递增运算符:它会先返回preb当前的旧值,再把preb往后移动一位。
- 所以
erase_after(preb++)实际传入的是preb原来的位置(也就是s2的前一个位置),这会把刚插入的s2删掉,而不是你要删除的s1。 - 同时
erase_after返回的是被删除元素(s2)的下一个迭代器,也就是原来的it指向的s1,此时it被赋值成这个迭代器,但后续循环中没有正确更新preb的位置,会导致逻辑混乱,比如重复处理同一个元素、迭代器失效,甚至死循环。
2. 使用++preb的正确逻辑
++preb是前置递增运算符:它会先把preb往后移动一位,再返回新的位置。
- 插入
s2后,preb原本指向s2的前一个位置,前置递增后,preb就指向了s2。此时erase_after(preb)会删除s2后面的元素——也就是你目标中的s1,符合预期。 erase_after返回的是s1的下一个元素,把it赋值成这个迭代器后,后续循环可以正常遍历链表剩余的元素。
内容的提问来源于stack exchange,提问作者harn
相关产品推荐
相关产品推荐

