C++遍历std::list时如何在advance()函数内正确删除指定元素
C++ std::list 迭代删除实现问题
我在尝试实现列表元素删除功能时遇到了问题,要求必须在advance()函数内部完成删除操作,以下代码是从实际项目中精简提取的最小复现用例:
#include <iostream> #include <list> #include <iterator> #include <algorithm> using namespace std; const int SCT_OSC_FILLED = 11; class OrderInfo { private: std::string id; public: OrderInfo(std::string a, int aStatusCode); std::string key(); int statusCode; }; OrderInfo::OrderInfo(std::string a, int aStatusCode) { id = a; statusCode = aStatusCode; } std::string OrderInfo::key() { return id; } std::list <OrderInfo> MasterOrders; void testList(); void add(OrderInfo ordInfo); void advance(OrderInfo ordInfo, std::list <OrderInfo> ::iterator& orderIter); void testList() { OrderInfo o1("1", 15); OrderInfo o2("2", 16); OrderInfo o3("3", SCT_OSC_FILLED); OrderInfo o4("4", 17); OrderInfo o5("5", SCT_OSC_FILLED); OrderInfo o6("6", 18); add(o1); add(o1); add(o2); add(o3); add(o4); add(o5); add(o6); for (auto v : MasterOrders) std::cout << v.key() << "\n"; } void add(OrderInfo ordInfo) { // 元素不存在时才加入MasterOrders bool alreadyInList = false; std::list <OrderInfo> ::iterator orderIter = MasterOrders.begin(); while (orderIter != MasterOrders.end()) { OrderInfo oi = *orderIter; alreadyInList = ordInfo.key() == oi.key(); if (alreadyInList) break; advance(ordInfo, orderIter); } if (!alreadyInList) MasterOrders.push_front(ordInfo); } void advance(OrderInfo ordInfo, std::list <OrderInfo> ::iterator& orderIter) { bool iterate = true; if (ordInfo.statusCode == SCT_OSC_FILLED) { orderIter = MasterOrders.erase(orderIter++); iterate = false; } if (iterate) orderIter++; } int main() { testList(); return 0; }
补充目标说明
我的目标是仅在advance()方法内部(该要求十分重要)删除状态为SCT_OSC_FILLED的ordInfo元素,保留其余元素。示例中的函数名均为演示所用,实际项目中这些函数还包含与列表操作无直接关联、但和OrderInfo处理相关的其他业务逻辑。
最终预期效果为:
- 列表中保留1份
o1副本,以及o2、o4、o6 - 删除
o3和o5,二者的OrderInfo.statusCode属性值均为SCT_OSC_FILLED
问题原因
代码存在两个核心错误:
- 判断对象错误:当前逻辑判断的是待插入元素
ordInfo的状态,而非迭代器指向的列表内已有元素的状态,导致插入非成交状态的元素时不会触发删除,插入成交状态元素时会误删列表内的正常元素。 - 迭代器更新逻辑错误:
std::list::erase本身会返回被删除元素的下一个有效迭代器,原写法orderIter = MasterOrders.erase(orderIter++);属于错误的迭代器操作,会引发未定义行为。
修正方案
仅需修改advance()函数内部逻辑即可,不需要改动其他代码,完全符合删除逻辑必须封装在advance()内的要求:
void advance(OrderInfo ordInfo, std::list <OrderInfo> ::iterator& orderIter) { // 判断当前迭代器指向的列表元素是否为需要删除的成交状态 if (orderIter->statusCode == SCT_OSC_FILLED) { // erase直接返回下一个有效迭代器,赋值后不需要额外移动指针 orderIter = MasterOrders.erase(orderIter); return; } // 不需要删除时,迭代器正常后移 orderIter++; }
修正后代码运行会按预期输出6、4、2、1,列表内不存在状态为SCT_OSC_FILLED的元素,重复插入的o1也只会保留一份。函数参数ordInfo保留不动,可继续承载其他业务逻辑。
内容的提问来源于stack exchange,提问作者ycomp
相关产品推荐
相关产品推荐

