2017-01-25 7 views
3

私は自分のベクトルを通過し、もはや必要としなかった要素を削除したいという問題に遭遇しました。それが失敗した理由は明らかですが、私は素朴なアプローチを試みたときにそれを見ませんでした。基本的には、要素を消去するとイテレータが無効になり、ループを続行できません。私は、次のされたもの:ベクトルを反復処理して特定の要素を削除する正しい方法は何ですか

#define GOOD 1 
    #define BAD 0 

    struct Element 
    { 
     Element(int isGood) : good(isGood){} 
     bool good; 
    }; 

    int main() 
    { 
     std::vector<Element> arr; 
     arr.push_back(Element(BAD)); 
     arr.push_back(Element(GOOD)); 
     arr.push_back(Element(BAD)); 
     arr.push_back(Element(GOOD)); 

    //__CLEAN ARRAY__// 
     for (auto it = arr.begin(); it != arr.end(); ++it) 
     { 
      if ((*it).good == false) arr.erase(it); 
     } 
    } 

だから、これは動作しないことは明らかだ、私はこれを行うための正しい/最良の方法は何であるか疑問に思いました。私の次のステップは、見つからない場合は新しいイテレータでループを再起動することですが、これもまた無駄に思えます。理想的には、ループは新しいイテレータで中断したところで続行されますか?

ありがとうございました。

+3

'std :: remove_if'について読んでください。 –

答えて

3

あなたが欲しい:

arr.erase(std::remove_if(arr.begin(), arr.end(), [](auto& obj){return obj.good == false;}), arr.end()); 

とその呼ばリムーブ消去イディオム:

https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom

しかし、あなたはループを修正したい場合は、それは可能です、あなたので、有効なイテレータの横のリターンを消去それを使用する必要があります:

for (auto it = arr.begin(); it != arr.end();) 
    { 
     if ((*it).good == false) 
     it = arr.erase(it); 
     else 
     it++; 
    } 
+0

ありがとうございます。私はちょうどremoveとremove_ifはコンテナのサイズを調整しないと言うつもりだった。ですから、もし私が10個の要素を持ち、2を取り除くと、反復子は8つの要素の最後に新しい終わりを返しますが、container.end()反復子はまだ10 + 1の終わりを過ぎて1つを指しています。この後、無駄なベクトルコンテナの種類はありませんか?また、これはループの最適化の機会に影響します。ループの繰り返しごとにarr.end()を再チェックする必要があるためです。 – Zebrafish

+0

std :: remove_ifはベクトルの新しいend()を返し、arr.eraseはそれを使って削除された要素をすべて削除します。したがって、この文が実行されると、arrには8つの要素があります。私はあなたの2番目の質問を理解するかどうかわからない、あなたがループを使用する場合は、確かに各繰り返しで.e​​nd()を確認する必要があります。 – marcinj

+0

ああ、あなたがremove_ifを実行した後で、範囲で消去を呼び出すことを意味します。私が言及した2番目のことは、コンパイラが変更されないことを知ることができれば、イテレータを毎回チェックする必要はないということです。コンパイラが行う最適化の一つではありませんか? – Zebrafish

関連する問題