範囲ベースの For ループで反復中に std::vector から要素を削除する
std::vector を反復して削除する特定の条件に一致する要素を見つけることは、プログラミングにおける一般的なタスクです。ただし、標準の範囲ベースの for ループ構文には課題があり、反復中に要素を消去しようとすると反復子が無効になる可能性があります。
範囲ベースの For ループ内での消去の問題
次のコード スニペットは問題を示しています。
for(iterator it = begin; it != end; ++it) { if(it->somecondition() ) { erase it } }
条件を満たす要素を削除することが目的ですが、このアプローチは正しくありません。要素が消去されると、イテレータは無効になります。そのイテレータを使用して反復処理を続けると、未定義の動作が発生します。
解決策 1: 明示的なイテレータ操作で通常の For ループを使用する
1 つの解決策は、通常の for ループを使用することです。明示的なイテレータ操作の場合:
for(iterator it = begin; it != end(container) /* !!! */;) { if (it->somecondition()) { it = vec.erase(it); // Returns the new iterator to continue from. } else { ++it; } }
ここでの決定的な違いに注意してください。各反復で明示的に end(container) を呼び出して、新しい終了イテレータを取得します。要素を削除すると元のイテレータが無効になるため、これが必要です。
解決策 2: std::remove_if と Erase を使用する
より効率的な代替方法は、std:: を組み合わせることです。 Remove_if と Erase():
iterator it = std::remove_if(begin, end, pred); vec.erase(it, vec.end());
std::remove_if は指定された述語に一致する要素を削除し、erase() はそれらを削除します。このアプローチにより、時間計算量が最初のソリューションの O(N2) から O(N) に軽減されます。
提供された例に固有のソリューション
指定された特定の例では、次のコードを使用して、特定のウィジェットに関連付けられた時限イベントを削除できます:
class remove_by_caller { public: remove_by_caller(AguiWidgetBase* pWidget) : mWidget(pWidget) {} template <typename T> // for now a template bool operator()(const T& pX) const { return pX.getCaller() == mWidget; } private: AguiWidgetBase* mWidget; }; std::vector<AguiTimedEvent>::iterator it = std::remove_if(timedEvents.begin(), timedEvents.end(), remove_by_caller(widget)); timedEvents.erase(it, timedEvents.end());
以上が範囲ベースの For ループでの反復中に std::vector から要素を安全に消去するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。