Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find and erase element from STL container while iterating

Tags:

c++

c++11

While iterating over a multimap I want to delete elements, but not only the element the iterator is pointing to.

for (vector<int> myVec : myVectors)
{
    auto range = myMultiMap.equal_range(myVector);
    for (auto it = range.first; it != range.second; ++it)
    {
        // secondPair is another element of this multimap
        auto secondPair = getSecondPair(it, myMultiMap);
        if (condition)
        {
            it = myMultiMap.erase(it);
            auto finder = myMultiMap.find(secondPair);
            // how can I delete secondPair?
        }
    }
}

Maybe it's the xy-problem here, so let me explain what I need this for: What I'm trying to do is to shorten a set of vector<int>. There are associated elements of type MyPair for each element. Those associated elements are stored in an unordered multimap.

typedef unordered_multimap < vector<int>, MyPair, SomeHash > MyMultiMap;

An element of the set<vector <int> > can be removed if all associated pairs in the multimap have been processed successfully. It won't be successful for most of them, so most of them are expected to remain in the set. My idea was to delete the elements from the multimap and if there are no associated elements in the multimap anymore, it means the element can be removed from the set. Here again I have the problem to remove elements from a set while iterating. Again, not only the one the iterator is pointing to.

like image 518
Sadik Avatar asked Oct 29 '22 23:10

Sadik


1 Answers

From cppreference on unordered_multimap::erase:

References and iterators to the erased elements are invalidated. Other iterators and references are not invalidated.

So I think that if you get an iterator to secondPair and secondPairIt != it then you can safely erase secondPairIt. You should also check that you are not invalidating the end of the range.

for (auto it = range.first; it != range.second;)
{
    if (condition)
    {
        auto secondPairIt = getSecondPairIt(it, myMultiMap); // Assume this is not end
        if (secondPairIt != it)
        {      
           if (secondPairIt == range.second)
               range.second = myMultiMap.erase(secondPairIt);
           else
               myMultiMap.erase(secondPairIt);
        }
        it = myMultiMap.erase(it);
    }
    else
    {
        ++it;
    }
}
like image 119
Guillaume Gris Avatar answered Nov 15 '22 08:11

Guillaume Gris