Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Erasing elements in a multimap while iterating

I'm writing a nodal path finding algorithm. I need to run through a multimap and delete elements out of it under certain conditions, but keep iterating through the multimap. Below is my code so far, it seems to work most of the time, but occasionally I get an error when doing nct_it++. Is it safe to erase the iterator pointer from the table before incrementing the iterator?

std::list<SinkSourceNodeConn>::iterator it;
std::multimap<SysNode*, SysNode*>::iterator nct_it;
SysNode* found_node = NULL;
nct_it = node_conn_table.begin();
while(nct_it != node_conn_table.end()) {

    // Find the node in the ever shrinking node connection table...
    if(nct_it->first == parent_node)
        found_node = nct_it->second;

    // Remove the table entry if we have found a node
    if(found_node) {
        // Search for the node in the expanded list. If it's not found, add it.
        bool found_the_node = false;
        for(it = m_sink_source_nodes_.begin(); it != m_sink_source_nodes_.end(); it++) {
            if(it->sink_source == sink_source && it->node == found_node)
                found_the_node = true;
        }
        if(!found_the_node) {
            recursion_list.push_back(found_node);
            recursion_list.unique();
            SinkSourceNodeConn ssnc;
            ssnc.node = found_node;
            ssnc.sink_source = sink_source;
            m_sink_source_nodes_.push_back(ssnc);
            if(found_node->GetPotential() < sink_source->GetPotential())
                found_node->SetPotential(sink_source->GetPotential());
        }
        found_node = NULL; // Unset the found node...
        node_conn_table.erase(nct_it);
        nct_it++;
    } else
        nct_it++;

}
like image 674
jasonlg3d Avatar asked Jan 24 '13 22:01

jasonlg3d


Video Answer


1 Answers

Is it safe to erase the iterator pointer from the table before incrementing the iterator?

No, erase will invalidate the iterator and you shouldn't increment it after that.

To do this properly, make use of the return value of erase - the iterator following the last removed element:

std::multimap<int, int> m;

for (auto it = m.begin(); it != m.end(); ) {
   if (condition)
       it = m.erase(it);
   else
       ++it;
}

In C++03, erase returns nothing, so you have to do this manualy by saving a copy of the iterator and incrementing it before you erase the original:

std::multimap<int, int> m;
typedef std::multimap<int, int>::iterator Iter;¸

for (Iter it = m.begin(); it != m.end(); ) {
   if ( /* some condition */ ) {
       Iter save = it;
       ++save;
       m.erase(it);
       it = save;
   } else
       ++it;
}
like image 155
jrok Avatar answered Sep 23 '22 15:09

jrok