2011-12-21 15 views
16

私はfor(int i = 0; i < vec.size(); i++)のようなループを持つベクトルをループしています。このループ内で、そのベクトルインデックスで要素の条件をチェックし、ある条件が真であれば、その要素を削除したいと思います。ループしている間に要素をベクターから削除する方法はありますか?

クラッシュすることなくベクター要素をループして削除するにはどうすればよいですか?

+4

'remove_if'と' erase'を多分使用できますか? http://en.wikipedia.org/wiki/Erase-remove_idiom – msandiford

+0

削除の削除:http://stackoverflow.com/questions/4175896/safe-way-to-continuously-erase-from-a-stdvector –

答えて

31

与えられた述語を満たすすべての要素をSTLコンテナから削除するという慣用的な方法は、remove-erase idiomを使用することです。

static bool pred(const std::string &s) { 
    // ... 
} 

std::vector<std::string> v; 
v.erase(std::remove_if(v.begin(), v.end(), pred), v.end()); 

あなたはインデックスを使用して主張する場合は、インデックスをインクリメントしないでください。アイデアは、その後predと言う、与えられた関数に(つまり、いくつかの要素のための真または偽生み出す機能です)述語を移動することですすべての要素のため、だけで削除されなかったものについて:

std::vector<std::string>::size_type i = 0; 
while (i < v.size()) { 
    if (shouldBeRemoved(v[i])) { 
     v.erase(v.begin() + i); 
    } else { 
     ++i; 
    } 
} 

しかし、これはより多くのコードとあまり慣用的であるだけでなく、(読み:C++プログラマは実際には「&を消去するのに対し、コードを見ています「イディオムをすぐに削除する」ということは、何が起こっているのかを即座に示す) eir要素を1つの連続したメモリブロックに格納するので、ベクトル終了以外の位置を消去すると、セグメントが消去された後のすべての要素も新しい位置に移動します。

+1

v.erase()の後にいくつの要素を殺したかを知る方法? (前と後のサイズを数えずに) – dynamic

+0

述語は関数である必要はありませんが、(特に要素を削除するかどうかを決定するために外部データを取得する必要がある場合は)ファンクタである可能性があります。 –

+1

@dynamic 'std :: vector'はランダムアクセスイテレータを備えているので、現在の終了イテレータから' std :: remove_if'によって返された新しい終了イテレータを単純に減算することでいくつの要素が消去されるかを知ることができます(例えば 'v.end () ')。 –

1

ベクトルを逆方向​​に反復する。そうすれば、まだ訪問していない要素に触れることはできません。

8

Erase-Remove Idiomを使用して、条件を指定する述語でremove_ifを使用します。

+0

リンクはSOにつながる。ここで破壊される可能性は低い。 –

9

(あなたがラムダを使用したり、述語を書きたくないので、例えば)あなたは/消去を削除する使用できない場合は、シーケンスコンテナ要素を除去するための標準的なイディオムを使用します。

for (auto it = v.cbegin(); it != v.cend() /* not hoisted */; /* no increment */) 
{ 
    if (delete_condition) 
    { 
     it = v.erase(it); 
    } 
    else 
    { 
     ++it; 
    } 
} 

可能な場合には、しかし、私はあなたがベクターから削除について具体的に求めている実感が、ちょうどSTDから項目を削除するにはコストがかかることを指摘したかった

#include <algorithm> 

v.erase(std::remove_if(v.begin(), v.end(), 
         [](T const & x) -> bool { /* decide */ }), 
     v.end()); 
+0

'for(auto it。。)これはコンパイルされますか? – ThomasMcLeod

+0

C++ 11コンパイラでは、yes。 – Vortico

1

::削除されたアイテムの後にすべての項目以来のベクトルなければなりません:/削除消去を好みます新しい場所にコピーしてください。コンテナから項目を削除する場合は、std :: listを使用する必要があります。 std :: list :: erase(item)メソッドは、消去されたものの後ろの値を指すイテレータを返すので、forループまたはwhileループで簡単に使用できます。 std :: listでうまくいくことは、消去されていない項目を指すイテレータがリストの存在を通じて有効であることです。たとえばdocs at cplusplus.comを参照してください。あなたが選択肢がなければ、新しい空のベクトルを作成して最初のベクトルから項目を追加してから、std :: swap(oldVec、newVec)を使用するだけです。非常に効率的です(コピーなし、内部ポインタの変更のみ)。

3
if(vector_name.empty() == false) { 
    for(int i = vector_name.size() - 1; i >= 0; i--) 
    { 
     if(condition) 
      vector_name.erase(vector_name.at(i)); 
    } 
} 

これは私に役立ちます。インデックスが既に消えていると考える必要はありません。

+0

消去する必要があります(vector_name.begin()+ i) = 0を指定すると、forループの繰り返しが発生しません – log0

+0

@ log0ランダムアクセスが可能ですなぜでしょうか?後者に同意します –

+0

'erase'はイテレータを引数として取り、' at'はベクトル**値**を返します例の文字列) – log0

関連する問題