std :: list :: erase无效

时间:2012-10-01 02:25:41

标签: c++ stl

如果其中一个对象的属性与条件匹配,我试图从对象列表中删除一个元素。这是我的功能,但是,在执行此操作然后打印内容后,erase()似乎没有任何效果。我在这做错了什么?

void FileReader::DeleteProcess(int id, list<Process> listToDeleteFrom)
{
    list<Process>::iterator process;

    for(process = listToDeleteFrom.begin(); process != listToDeleteFrom.end(); process++)
    {
        if (process -> ID == id)
        {
            listToDeleteFrom.erase(process);
        }
    }
}

3 个答案:

答案 0 :(得分:10)

首先,您需要通过引用传递列表;你的代码正在处理一个副本,因此它所做的更改不会影响调用者的列表:

void FileReader::DeleteProcess(int id, list<Process> & listToDeleteFrom)
                                                     ^

其次,擦除列表元素会使引用该元素的任何迭代器无效,因此尝试继续进行迭代将导致未定义的行为。如果只有一个要移除的元素,则在调用erase之后直接从函数返回;否则,循环需要结构如下:

for (auto it = list.begin(); it != list.end(); /* don't increment here */) {
    if (it->ID == id) {
        it = list.erase(it);
    } else {
        ++it;
    }
}

答案 1 :(得分:6)

当迭代器迭代erase()时,调用list使迭代器无效。将要删除的元素添加到第二个列表,然后将其删除。

另请注意,您是按值传递列表而不是使用引用或指针。您的意思是使用list<Process>& listToDeleteFrom还是list<Process>* listToDeleteFrom

答案 2 :(得分:1)

您没有看到任何更改反映的原因是您的列表未通过引用传递,因此您只是从列表副本中删除元素。

将其更改为:

void FileReader::DeleteProcess(int id, list<Process> &listToDeleteFrom) //note &

这将在函数中保留相同的语法并修改原始文件。

但是,删除元素的方式有点次优。如果你有C ++ 11,下面将删除你的失效问题,并且使用为该作业设计的现有算法更加惯用:

listToDeleteFrom.erase ( //erase matching elements returned from remove_if
    std::remove_if( 
        std::begin(listToDeleteFrom), 
        std::end(listToDeleteFrom), 
        [](const Process &p) { //lambda that matches based on id
            return p->ID == id;
        }
    ),
    std::end(listToDeleteFrom) //to the end of the list
);

请注意保留std::list<>::erase以实际删除匹配的元素。这被称为擦除删除习语。