C++ list去重函数触发Segmentation Fault问题求助
解决你的Segmentation Fault段错误问题
我一眼就看出你代码里的问题了——是迭代器的处理逻辑出错导致的段错误,咱们一步步拆解:
首先看你处理重复元素的这段代码:
if (!res.second) { next = ++iter; _list.erase(iter); iter = next; continue; }
这里的核心错误是:你先把iter递增到下一个元素,然后去erase这个已经移动后的iter。这会导致两个问题:
- 你根本没删除掉那个重复的元素(你本来要删的是原来
iter指向的元素); std::list::erase会让被删除的迭代器失效,而你此时的iter和next是同一个对象(因为next = ++iter是把递增后的iter赋值给next),所以iter变成了失效的迭代器,后续循环中使用它必然触发段错误。
正确的修复方式
有几种简洁且安全的写法,推荐按复杂度从低到高选择:
写法1:利用erase的返回值(C++11及以上)
std::list::erase在C++11之后会返回被删除元素的下一个有效迭代器,所以我们可以直接用它来更新iter,完全不需要额外的next变量:
void RemoveDuplicates(list<int>& _list) { set<int> uniqueElements; auto iter = _list.begin(); while (iter != _list.end()) { auto res = uniqueElements.insert(*iter); if (!res.second) { // erase返回下一个有效迭代器,直接赋值给iter iter = _list.erase(iter); } else { ++iter; } } }
写法2:提前保存下一个迭代器(兼容C++03)
如果需要兼容旧标准,我们可以先保存当前iter的下一个位置,再删除当前元素,最后把iter切换到保存的位置:
void RemoveDuplicates(list<int>& _list) { set<int> uniqueElements; list<int>::iterator iter = _list.begin(); list<int>::iterator next; pair<set<int>::iterator, bool> res; while (iter != _list.end()) { res = uniqueElements.insert(*iter); if (!res.second) { next = next(iter); // 提前获取下一个迭代器 _list.erase(iter); iter = next; } else { ++iter; } } }
写法3:利用iter++的特性(简洁版)
iter++会先返回当前迭代器的副本(用于erase),再把iter移动到下一个位置,这样也能避免失效问题:
if (!res.second) { // erase的是递增前的iter,此时iter已经指向了下一个元素 _list.erase(iter++); } else { ++iter; }
额外优化建议
如果你的项目使用C++11及以上标准,用auto替代冗长的迭代器声明,代码会更简洁易读,就像写法1里那样。
内容的提问来源于stack exchange,提问作者Hana
相关产品推荐
相关产品推荐

