30

特定のプロパティを持つ要素をstd::vectorコンテナーまたは他のコンテナーから削除するタスクは、機能的なスタイルの実装に適しています。ループ、メモリの割り当て解除、データの移動を正しく行う必要はありません。

ただし、C++ でこれを行う標準的な方法は、次のイディオムのようです。

std::vector<int> ints;
...
ints.erase(
    std::remove_if(ints.begin(), 
                   ints.end(),
                   [](int x){return x < 0;}),
    ints.end());

この例では、ゼロ未満のすべての要素を整数ベクトルから削除します。

醜いだけでなく、間違った使い方も簡単だと思います。std::remove_if渡された反復子のみを取得するため、ベクトルのサイズを (その名前が示すように) 変更できないことは明らかです。しかし、私を含む多くの開発者は、最初はそれを理解していません。

では、これを達成するためのより安全で、できればよりエレガントな方法はありますか? そうでない場合、なぜですか?

4

2 に答える 2

27

醜いだけでなく、間違った使い方も簡単だと思います。

心配しないでください、最初はみんなそうでした。

std::remove_if はベクトルのサイズを (その名前が示すように) 変更できないことは明らかです。しかし、私を含む多くの開発者は、最初はそれを理解していません。

同じ。それは皆を混乱させます。おそらくremove_if、何年も前に呼び出されるべきではありませんでした。後知恵、え?

では、これを達成するためのより安全で、できればよりエレガントな方法はありますか?

いいえ

そうでない場合、なぜですか?

これは、アイテムを削除するとイテレータが無効になるコンテナーからアイテムを削除するときに、パフォーマンスを維持する最も安全で洗練された方法だからです。

予想:

私にできることはありますか?

はい、このイディオムを関数にラップします

template<class Container, class F>
auto erase_where(Container& c, F&& f)
{
    return c.erase(std::remove_if(c.begin(), 
                                  c.end(),
                                  std::forward<F>(f)),
                   c.end());    
}

動機付けの例の呼び出しは次のようになります。

auto is_negative = [](int x){return x < 0;};
erase_where(ints, is_negative);

また

erase_where(ints, [](int x){return x < 0;});
于 2016-04-03T10:59:03.897 に答える
18

std::experimental::erase_ifこれは、アルゴリズムを通じてすぐに C++17 対応コンパイラで利用できるようになります。

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#include <experimental/vector>

int main()
{
    std::vector<int> ints { -1, 0, 1 };   
    std::experimental::erase_if(ints, [](int x){
        return x < 0;
    });
    std::copy(ints.begin(), ints.end(), std::ostream_iterator<int>(std::cout, ","));
}

0,1 を出力する実際の

于 2016-04-05T18:26:29.333 に答える