You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

问题原因

代码存在两个核心错误:

  1. 判断对象错误:当前逻辑判断的是待插入元素ordInfo的状态,而非迭代器指向的列表内已有元素的状态,导致插入非成交状态的元素时不会触发删除,插入成交状态元素时会误删列表内的正常元素。
  2. 迭代器更新逻辑错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 09:51:30