2012-10-01 2 views
1

Я пытаюсь удалить элемент из списка объектов, если одно из свойств объекта соответствует условию. Это моя функция сделать это, однако, после выполнения этой операции, а затем печати содержимого, erase(), кажется, не имеет никакого эффекта. Что я здесь делаю неправильно?std :: list :: erase not working

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); 
     } 
    } 
} 

ответ

6

erase() Вызов, когда итератор итерация над list аннулированию итератора. Добавьте элементы для удаления во второй список, а затем удалите их.

Также обратите внимание, что вы передаете список по значению, а не используя ссылку или указатель. Вы имели в виду использовать list<Process>& listToDeleteFrom или list<Process>* listToDeleteFrom?

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; 
    } 
} 
+0

Большое вам спасибо! Я полностью забыл пройти по ссылке –

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 там на самом деле удалить элементы, совпадение. Это называется стиранием-удалением идиомы.