1

私は現在、上記のプログラムのある時点でリストを使用するプログラムを作成しています.3つの3つのリストa、b、cを反復処理し、aに表示される場合はbとcの要素を削除します。私はそのようにやっています:

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

ただし、これにより「リスト反復子はインクリメントできません」というエラーが発生します。これを修正するにはどうすればよいですか?

4

3 に答える 3

1

あなたの消去呼び出しから、あなたはしたいです

  1. OpenList アイテムが ClosedList リストにある場合は削除します
  2. 近隣アイテムが ClosedListlist から見つかった場合は削除します

ネストされたループではなく、コードを 2 つのループに分割することをお勧めします。次に例を示します。

1. OpenList アイテムが ClosedList リストにある場合は削除します

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

更新: ノード タイプに operator== を定義することを忘れないでください。たとえば、ノードに getId インターフェイスがある場合:

bool operator==(const Node& lhs, const Node& rhs)
{
  return lhs.getId() == rhs.getId();
}
于 2013-05-01T11:25:17.100 に答える
0

の戻り値を正しく使用して新しい反復子を取得しましたが、ループの現在の反復の最後にこの反復子がすぐに取得さ.eraseれることを忘れていました。++の結果が.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 が示唆するように、標準アルゴリズムを使用することで、この問題を完全に回避できます。

于 2013-05-01T11:30:35.257 に答える