Can you remove elements from a std::list while iterating through it?

后端 未结 13 874
长情又很酷
长情又很酷 2020-11-22 06:30

I\'ve got code that looks like this:

for (std::list::iterator i=items.begin();i!=items.end();i++)
{
    bool isActive = (*i)->update();
    /         


        
相关标签:
13条回答
  • 2020-11-22 06:33

    You can write

    std::list<item*>::iterator i = items.begin();
    while (i != items.end())
    {
        bool isActive = (*i)->update();
        if (!isActive) {
            i = items.erase(i); 
        } else {
            other_code_involving(*i);
            i++;
        }
    }
    

    You can write equivalent code with std::list::remove_if, which is less verbose and more explicit

    items.remove_if([] (item*i) {
        bool isActive = (*i)->update();
        if (!isActive) 
            return true;
    
        other_code_involving(*i);
        return false;
    });
    

    The std::vector::erase std::remove_if idiom should be used when items is a vector instead of a list to keep compexity at O(n) - or in case you write generic code and items might be a container with no effective way to erase single items (like a vector)

    items.erase(std::remove_if(begin(items), end(items), [] (item*i) {
        bool isActive = (*i)->update();
        if (!isActive) 
            return true;
    
        other_code_involving(*i);
        return false;
    }));
    
    0 讨论(0)
  • 2020-11-22 06:36

    Use std::remove_if algorithm.

    Edit: Work with collections should be like: 1. prepare collection. 2. process collection.

    Life will be easier if you won't mix this steps.

    1. std::remove_if. or list::remove_if ( if you know that you work with list and not with the TCollection )
    2. std::for_each
    0 讨论(0)
  • 2020-11-22 06:36

    I think you have a bug there, I code this way:

    for (std::list<CAudioChannel *>::iterator itAudioChannel = audioChannels.begin();
                 itAudioChannel != audioChannels.end(); )
    {
        CAudioChannel *audioChannel = *itAudioChannel;
        std::list<CAudioChannel *>::iterator itCurrentAudioChannel = itAudioChannel;
        itAudioChannel++;
    
        if (audioChannel->destroyMe)
        {
            audioChannels.erase(itCurrentAudioChannel);
            delete audioChannel;
            continue;
        }
        audioChannel->Mix(outBuffer, numSamples);
    }
    
    0 讨论(0)
  • 2020-11-22 06:42

    Iterating backwards avoids the effect of erasing an element on the remaining elements to be traversed:

    typedef list<item*> list_t;
    for ( list_t::iterator it = items.end() ; it != items.begin() ; ) {
        --it;
        bool remove = <determine whether to remove>
        if ( remove ) {
            items.erase( it );
        }
    }
    

    PS: see this, e.g., regarding backward iteration.

    PS2: I did not thoroughly tested if it handles well erasing elements at the ends.

    0 讨论(0)
  • 2020-11-22 06:48

    Here's an example using a for loop that iterates the list and increments or revalidates the iterator in the event of an item being removed during traversal of the list.

    for(auto i = items.begin(); i != items.end();)
    {
        if(bool isActive = (*i)->update())
        {
            other_code_involving(*i);
            ++i;
    
        }
        else
        {
            i = items.erase(i);
    
        }
    
    }
    
    items.remove_if(CheckItemNotActive);
    
    0 讨论(0)
  • 2020-11-22 06:49

    If you think of the std::list like a queue, then you can dequeue and enqueue all the items that you want to keep, but only dequeue (and not enqueue) the item you want to remove. Here's an example where I want to remove 5 from a list containing the numbers 1-10...

    std::list<int> myList;
    
    int size = myList.size(); // The size needs to be saved to iterate through the whole thing
    
    for (int i = 0; i < size; ++i)
    {
        int val = myList.back()
        myList.pop_back() // dequeue
        if (val != 5)
        {
             myList.push_front(val) // enqueue if not 5
        }
    }
    

    myList will now only have numbers 1-4 and 6-10.

    0 讨论(0)
提交回复
热议问题