为什么std :: remove_copy_if()实际上没有删除?

Sco*_*ley 17 c++ stl

这可能是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;
}
Run Code Online (Sandbox Code Playgroud)

它输出:

-2 0 -1 0 1 2 
0 0 1 2 
-2 0 -1 0 1 2 
Run Code Online (Sandbox Code Playgroud)

我期待如下所见:

-2 0 -1 0 1 2 
0 0 1 2 
0 0 1 2 ? ? ?
Run Code Online (Sandbox Code Playgroud)

哪里?可以是任何价值.但我很惊讶地发现输入范围是未触及的,并且返回值不能与(在这种情况下)std :: vector :: erase()一起使用.(返回值是输出迭代器.)

Dav*_*eas 20

这可能是STL中最糟糕的命名功能吗?

一些背景信息:在标准库(或原始STL)中,有三个概念,容器,到这些容器的迭代器和应用于迭代器的算法.迭代器充当范围元素的游标和访问者,但没有对容器的引用(如前所述,甚至可能没有底层容器).

这种分离有一个很好的功能,你可以将算法应用于不属于容器的元素范围(考虑像std::istream_iteratoror的迭代器适配器std::ostream_iterator)或属于容器的不考虑所有元素(std::sort( v.begin(), v.begin()+v.size()/2 )缩短容器的前半部分) ).

负面的一面是,因为算法(和迭代器)并不真正知道容器,它们无法真正修改它,它们只能修改存储的元素(这是他们可以访问的).变异算法,像std::removestd::remove_if在这个前提下工作:它们覆盖与条件不匹配的元素,有效地它们从容器中删除,但它们不会修改容器,只修改包含的值,这是第二步中的调用者在的擦除,删除成语:

v.erase( std::remove_if( v.begin(), v.end(), pred ),
         v.end() );
Run Code Online (Sandbox Code Playgroud)

此外,对于变异算法(执行变更的算法),例如std::remove通过添加copy名称来命名的非变异版本:std::remove_copy_if.没有任何XXXcopyYYY算法被认为是改变输入序列(尽管它们可以使用别名迭代器).

虽然这不是命名的借口,但std::remove_copy_if我希望它有助于理解算法给出其名称的作用:remove_if将修改范围的内容并产生一个范围,其中所有与谓词匹配的元素都已被删除(返回的范围)是由算法的第一个参数形成的返回迭代器).std::remove_copy_if做同样的事情,但它不是修改基础序列,而是创建一个序列的副本,其中已删除与谓词匹配的那些元素.也就是说,所有*copy*算法等同于复制然后应用原始算法(请注意,等价是逻辑的,std::remove_copy_if只需要一个OutputIterator,这意味着它不可能复制,然后应用复制的范围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;
}
Run Code Online (Sandbox Code Playgroud)


fre*_*low 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());
Run Code Online (Sandbox Code Playgroud)

现在v将包含“好”元素,并将w包含“坏”元素。