【问题标题】:Erasing elements in a multimap while iterating迭代时擦除多图中的元素
【发布时间】:2013-01-24 22:19:06
【问题描述】:

我正在编写一个节点寻路算法。我需要在特定条件下运行多图并从中删除元素,但要继续遍历多图。下面是我到目前为止的代码,它似乎大部分时间都可以工作,但是在执行 nct_it++ 时偶尔会出错。在递增迭代器之前从表中擦除迭代器指针是否安全?

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

}

【问题讨论】:

  • std::remove_if 不适合你吗?
  • 这不会将迭代器返回到地图的末尾,这会提前结束我的循环吗?
  • 我不明白。 std::remove_if 没有循环。它遍历您在调用中指定的范围。
  • 它会永久结束这个循环:while(nct_it != node_conn_table.end()) {
  • 但是使用std::remove_if,您将删除该循环并在remove_if 调用中指定node_conn_table.begin()node_conn_table.end()

标签: c++ iterator multimap


【解决方案1】:

在递增迭代器之前从表中擦除迭代器指针是否安全?

不,erase 将使迭代器无效,之后您不应增加它。

要正确执行此操作,请使用 erase 的返回值 - 最后一个删除元素之后的迭代器:

std::multimap<int, int> m;

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

在 C++03 中,erase 不返回任何内容,因此您必须手动执行此操作,方法是保存迭代器的副本并在删除原始迭代器之前将其递增:

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

【讨论】:

  • 你不能简单地写m.erase(it++);而不是使用临时变量吗?
  • @Kira 阅读此答案的第二行“不,erase 将使迭代器无效,之后您不应再增加它。”
  • 其实m.erase(it++)会将it的当前值设置为erase的参数,将其递增,然后调用erase(使用预递增值),使其安全致电m.erase(it++)
【解决方案2】:

这样不是更好吗?

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;
        ++it;
        m.erase(save);
    } else
       ++it;
}

【讨论】:

    猜你喜欢
    • 2014-06-11
    • 2020-06-08
    • 2011-03-22
    • 2013-01-28
    • 1970-01-01
    • 2011-07-13
    • 1970-01-01
    • 2018-09-04
    • 1970-01-01
    相关资源
    最近更新 更多