在List语法中删除正确的迭代

时间:2013-05-01 11:00:49

标签: c++

我正在编写一个程序,在所述程序中的某一点使用列表我想迭代3个三个列表a,b和c,并删除b和c中的任何元素(如果它出现在a中)。我是这样做的:

//remove elements from OpenList that are in ClosedList
    for(list<Node> :: iterator cloIt = ClosedList.begin(); cloIt != ClosedList.end(); cloIt++)
    {
        for(list<Node> :: iterator opIt = OpenList.begin(); opIt != OpenList.end(); opIt++)
        {
            for(list<Node> :: iterator neigIt = Neighbour.begin(); neigIt != Neighbour.end(); neigIt++)
            {
                if (*cloIt == *opIt)
                {
                    opIt = OpenList.erase(opIt);

                }
                if (*cloIt == *neigIt)
                {
                    neigIt = Neighbour.erase(neigIt);
                }
            }
        }
    }

然而,这导致我得到“List iterator not incrementable”错误 我怎么能解决这个问题?

3 个答案:

答案 0 :(得分:1)

从你的擦除电话中,你想要

  
      
  1. 删除OpenList项目(如果在ClosedList列表中找到它们)
  2.   
  3. 删除从ClosedListlist
  4. 中找到的邻居项目   

您最好将代码分成两个循环,而不是嵌套循环,例如:

1.如果在ClosedList列表中找到它们,则删除OpenList项目

for(auto cloIt = ClosedList.begin(); cloIt != ClosedList.end(); ++cloIt)
{
   OpenList.remove_if([&](const Node& n){ return n == *colIt; } );
}

2.如果从ClosedListlist

找到它们,则删除它们
for(auto cloIt = ClosedList.begin(); cloIt != ClosedList.end(); ++cloIt)
{
   Neighbour.remove_if([&](const Node& n){ return n == *colIt; } );
}

显然以前的代码是重复的,您可以为此编写一个通用函数:

void RemoveItem(std::list<Node>& node_list, std::list<Node>& node_list2)
{
   for(auto cloIt = node_list2.begin(); cloIt != node_list2.end(); ++cloIt)
   {
      node_list.remove_if([&](const Node& n){ return n == *colIt; } );
   }
}

现在你可以打电话:

RemoveItem(OpenList, CloseList);
RemoveItem(Neighbour, CloseList);

<强>更新 不要忘记为Node类型定义operator ==,例如,如果node具有getId接口:

bool operator==(const Node& lhs, const Node& rhs)
{
  return lhs.getId() == rhs.getId();
}

答案 1 :(得分:0)

  

我怎么能解决这个问题?

最好的方法是使用标准算法,让他们为您进行迭代,搜索和/或条件删除。

您可以将std::list的{​​{3}}成员函数与lambda谓词一起使用,该谓词检查该元素是否包含在列表a中:

#include <algorithm>

// ...

b.remove_if(
    [&a] (Node const& n)
    {
        return (std::find(begin(a), end(a), n) != a.end());
    });

如果c中包含元素,则删除a中的元素。

另一种可能性是使用std::for_each()来迭代a的所有元素,并将其从bc中删除:

#include <algorithm>

// ...

std::for_each(begin(a), end(a),
    [&b, &c] (Node const& n)
    {
        b.remove(n);
        c.remove(n);
    });

答案 2 :(得分:0)

您已正确使用.erase的返回值来获取新迭代器,但忘记了此迭代器在循环的当前迭代结束时立即获得++ d;如果.erase的结果为.end,则此操作无效。

(你真的非常幸运,你得到了一个诊断,试图增加你现在无效的迭代器 - 标准保证绝对没有关于这种情况。)

当您没有++时,您需要.erase

一般模式如下:

for (typename list<T>::iterator it = l.begin(), end = l.end(); it != end; )
{
    // ^^ NB. no "it++" in the loop introduction!

    if (foo(*it)) {
       // condition satisfied; do the erase, and get the next
       // iterator from `.erase` and NOT through incrementing
       it = l.erase(it);
    }
    else {
       // no erasure; do the increment only in this case
       it++;
    }
}

正如Andy建议的那样,你可以通过使用标准算法完全避免这个问题。