22

これはSTLで最悪の名前の関数でしょうか?(レトリックの質問)

std :: remove_copy_if()は、実際には削除を行っていないようです。私が知る限り、それはcopy_if_notのように動作します。

否定は少し紛らわしいですが、std :: not1()で回避できますが、この関数が削除と何の関係があるのか​​理解できないため、何かを誤解している可能性があります-何かが欠けていますか?

そうでない場合、コンテナから要素を条件付きで削除(移動?)して別のコンテナに配置するためのSTLアルゴリズムはありますか?

読者が混乱しないように編集して例を追加します。

次のプログラムは、入力範囲(V1)をそのままにしておくように見えます。

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

using std::cout;
using std::endl;

int main (void)
{
    std::vector<int> V1, V2;
    V1.push_back(-2);
    V1.push_back(0);
    V1.push_back(-1);
    V1.push_back(0);
    V1.push_back(1);
    V1.push_back(2);

    std::copy(V1.begin(), V1.end(), std::ostream_iterator<int>(cout, " "));
    cout << endl;

    std::remove_copy_if(
        V1.begin(),
        V1.end(),
        std::back_inserter(V2),
        std::bind2nd(std::less<int>(), 0));

    std::copy(V2.begin(), V2.end(), std::ostream_iterator<int>(cout, " "));
    cout << endl;
    std::copy(V1.begin(), V1.end(), std::ostream_iterator<int>(cout, " "));
    cout << endl;
}

以下を出力します。

-2 0 -1 0 1 2 
0 0 1 2 
-2 0 -1 0 1 2 

私は期待していたので、次のようなものを参照してください:

-2 0 -1 0 1 2 
0 0 1 2 
0 0 1 2 ? ? ?

どこ ?任意の値にすることができます。しかし、入力範囲が変更されておらず、戻り値が(この場合)std :: vector :: Erase()で使用できないことに驚きました。(戻り値は出力イテレータです。)

4

5 に答える 5

25

これはSTLで最悪の名前の関数でしょうか?

少し背景情報:標準ライブラリ(または元のSTL)には、コンテナ、それらのコンテナへのイテレータ、およびイテレータに適用されるアルゴリズムの3つの概念があります。イテレータは、範囲の要素へのカーソルおよびアクセサとして機能しますが、コンテナへの参照はありません(前述のように、基になるコンテナさえない場合があります)。

この分離には、コンテナに属していない要素の範囲にアルゴリズムを適用できる(またはのようなイテレータアダプタを検討するstd::istream_iteratorstd::ostream_iterator、またはコンテナに属するすべての要素を考慮しない(std::sort( v.begin(), v.begin()+v.size()/2 )コンテナの前半を短縮する)という優れた機能があります。 )。

マイナス面は、アルゴリズム(およびイテレーター)がコンテナーを実際には認識していないため、コンテナーを実際に変更することはできず、格納されている要素(アクセスできるもの)のみを変更できることです。std::removeこの前提のような、またはこの前提で機能する変更アルゴリズムstd::remove_if:条件に一致しない要素を上書きして、コンテナから効果的に削除しますが、コンテナを変更せず、含まれている値のみを変更します。これは、2番目のステップで呼び出し元に任されます。消去-削除イディオムの:

v.erase( std::remove_if( v.begin(), v.end(), pred ),
         v.end() );

さらに、変更アルゴリズム(変更を実行するアルゴリズム)の場合、名前に次のように追加することで名前がstd::remove付けられた非変更バージョンがあります。どのアルゴリズムも入力シーケンスを変更するとは見なされません(ただし、エイリアシングイテレータを使用する場合は変更できます)。copystd::remove_copy_ifXXXcopyYYY

これは実際にはの命名の言い訳にはなりませんがstd::remove_copy_if、アルゴリズムがその名前で何をするかを理解するのに役立つことを願っています:範囲の内容remove_ifを変更し、述語に一致するすべての要素が削除された範囲(返された範囲)を生成します返されたイテレータに対するアルゴリズムの最初の引数によって形成されるものです)。同じことを行いますが、基になるシーケンスを変更するのではなく、述語に一致する要素が削除されたシーケンスのコピーを作成します。つまり、すべての*コピー*アルゴリズムは、コピーしてから元のアルゴリズムを適用することと同等です(同等性は論理的であり、必要なのはstd::remove_copy_ifstd::remove_copy_ifOutputIterator 。これは、を適用して、コピーしてからコピーした範囲をたどることができなかったことを意味しstd::remove_ifます。

同じ推論を他のミューティングアルゴリズムに適用できます。範囲内の値をreverse逆にし(イテレータはコンテナにアクセスしないことを忘れないでください)、範囲内の要素を逆の順序で範囲を分離するためにコピーします。reverse_copy

そうでない場合、コンテナから要素を条件付きで削除(移動?)して別のコンテナに配置するためのSTLアルゴリズムはありますか?

STLにはそのようなアルゴリズムはありませんが、簡単に実装できます。

template <typename FIterator, typename OIterator, typename Pred>
FIterator splice_if( FIterator first, FIterator last, OIterator out, Pred p )
{
   FIterator result = first;
   for ( ; first != last; ++first ) {
      if ( p( *first ) ) {
         *result++ = *first;
      } else {
         *out++ = *first;
      }
   }
   return result;
}
于 2012-08-13T10:45:18.003 に答える
5

コンテナから要素を条件付きで削除(移動?)して別のコンテナに配置するためのSTLアルゴリズムはありますか?

私が考えることができる最も近いものはstd::stable_partition

std::vector<int> v;
// ...
auto it = std::stable_partition(v.begin(), v.end(), pick_the_good_elements);
std::vector<int> w(std::make_move_iter(it), std::make_move_iter(v.end()));
v.erase(it, v.end());

vこれで、「良い」要素wが含まれ、「悪い」要素が含まれます。

于 2012-08-13T08:20:14.370 に答える
2

そうでない場合、コンテナから要素を条件付きで削除(移動?)して別のコンテナに配置するためのSTLアルゴリズムはありますか?

あまり。変更アルゴリズムは、コンテナー内の要素を(C ++の意味ではなく)「移動」することはできますが、コンテナーの長さを変更することはできません。したがって、removeアルゴリズムはと呼ぶことができますprepare_for_removal

ちなみに、C++11はstd::copy_ifを提供します。これにより、で面白いロジックゲームをプレイすることなく、選択した要素をあるコンテナから別のコンテナにコピーできますremove_copy_if

于 2012-08-13T04:30:02.837 に答える
1

そうです、それが何をするのか... std :: remove_copy_ifはベクトルをコピーし、predに一致するものをすべて削除します。

std :: remove_if ...条件に応じて削除します(つまり、シャッフルします)。

于 2012-08-13T04:21:27.047 に答える
0

remove私は、それがこの機能ファミリーの最良の名前ではないことに同意します。

しかし、Lucが言ったように、それがそのように機能するのには理由があり、彼が言及するGoTWアイテムは、それがどのように機能するかを説明しています。remove_ifremoveとまったく同じように機能します-これはあなたが期待することです。

このウィキブックスの記事も読むことをお勧めします。

于 2012-08-13T04:29:54.480 に答える