如果其中一个对象的属性与条件匹配,我试图从对象列表中删除一个元素。这是我的功能,但是,在执行此操作然后打印内容后,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);
}
}
}
答案 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
以实际删除匹配的元素。这被称为擦除删除习语。