std::list::erase not working

后端 未结 3 1100
天涯浪人
天涯浪人 2020-12-20 08:13

I am trying to delete an element from a list of objects if one of the object\'s properties matches a condition. This is my function to do so, however, after performing this

相关标签:
3条回答
  • 2020-12-20 08:36

    The reason you see no changes reflected is that your list is not being passed by reference, so you are only removing elements from a copy of the list.

    Change it to this:

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

    This will keep the same syntax in the function and modify the original.

    However, the way you're deleting the elements is a bit sub-optimal. If you have C++11, the following will remove your invalidation problem, and is more idiomatic, using an existing algorithm designed for the job:

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

    Note the keeping of std::list<>::erase in there to actually erase the elements that match. This is known as the erase-remove idiom.

    0 讨论(0)
  • 2020-12-20 08:37

    Calling erase() when an iterator is iterating over the list invalidates the iterator. Add the elements to erase to a second list then remove them afterwards.

    Also note that you are passing the list by value rather than using a reference or a pointer. Did you mean to use list<Process>& listToDeleteFrom or list<Process>* listToDeleteFrom?

    0 讨论(0)
  • 2020-12-20 08:41

    First, you need to pass the list by reference; your code is working on a copy, so changes it makes won't affect the caller's list:

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

    Second, erasing a list element invalidates any iterator that refers to that element, so attempting to carry on iterating afterwards will cause undefined behaviour. If there will only be one element to remove, then return from the function straight after the call to erase; otherwise, the loop needs to be structured something like:

    for (auto it = list.begin(); it != list.end(); /* don't increment here */) {
        if (it->ID == id) {
            it = list.erase(it);
        } else {
            ++it;
        }
    }
    
    0 讨论(0)
提交回复
热议问题