C++ list删除重复元素触发段错误的问题排查
C++ list删除重复元素触发段错误问题解析
核心错误原因
- 对
std::list执行erase()操作后,指向被删除元素的迭代器会直接失效,你代码中调用v3.erase(itip)后,itip已经是无效迭代器,外层循环本轮结束时执行itip++属于对无效迭代器做自增操作,直接访问非法内存,触发段错误。 - 你代码中删除
it后直接执行了内层break,没有触发it++,所以没有暴露it的失效问题,但itip的失效是必现问题。
注意:常见认知误区:list是链表结构,erase操作不会导致迭代器失效。该认知仅适用于指向未被删除节点的迭代器,指向被删除节点本身的迭代器一定会失效,不可继续访问或做自增/自减操作。
修复方案
方案1:基于erase返回值适配你的双重循环逻辑
std::list::erase执行完成后会返回指向被删除元素下一个位置的有效迭代器,你可以用返回值更新迭代器,避免操作失效迭代器:
int main() { vector<pair<int,int>> v1 = {make_pair(1,2),make_pair(3,4)}; vector<pair<int,int>> v2 = {make_pair(2,3),make_pair(5,6)}; list<int>v3; list<int>::iterator it; list<int>::iterator itip; vector<pair<int,int>> v4; int count = 0; for (auto &i :v1) { v3.push_back(i.first); v3.push_back(i.second); } for (auto &i :v2) { v3.push_back(i.first); v3.push_back(i.second); } // 修正迭代器自增逻辑:仅未触发删除时才手动自增 for (itip=v3.begin(); itip != v3.end(); ) { bool has_erased = false; for (it = v3.begin() ; it != v3.end(); ) { if (*itip == *it) { if (itip != it ) { it = v3.erase(it); itip = v3.erase(itip); cout<<"List After erased"<<endl; for (auto &i : v3) { cout<<i<<"\t"; } cout<<"\nList After erased"<<endl; has_erased = true; break; } } if (!has_erased) { ++it; } } if (!has_erased) { ++itip; } } cout<<endl; for (auto &i : v3) { cout<<i<<"\t"; } return 0; }
方案2:更高效的去重实现(推荐)
如果需求是删除所有出现过多次的元素,不需要嵌套循环,用哈希表统计元素出现次数后单次遍历删除即可,时间复杂度更低:
// 统计每个元素出现次数 unordered_map<int, int> num_cnt; for (auto num : v3) { num_cnt[num]++; } // 遍历删除出现次数大于1的元素 for (auto it = v3.begin(); it != v3.end(); ) { if (num_cnt[*it] > 1) { it = v3.erase(it); } else { ++it; } }
内容的提问来源于stack exchange,提问作者Nitesh Prabhat
相关产品推荐
相关产品推荐

