一尘不染

为什么不能使用std :: remove_if从std :: set中删除字符串?

algorithm

我有一组字符串:

set <wstring> strings;
// ...

我希望根据谓词删除字符串,例如:

std::remove_if ( strings.begin(), strings.end(), []( const wstring &s ) -> bool { return s == L"matching"; });

尝试执行此操作时,出现以下编译器错误:

c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\algorithm(1840): error C2678: binary '=' : no operator found which takes a left-hand operand of type 'const std::basic_string<_Elem,_Traits,_Ax>'

该错误似乎表明std::string没有按值复制构造函数(这是非法的)。是它在某种程度上不好用std::remove_ifstd::set?我是否应该做其他事情,例如,set::find()随后的几次迭代set::erase()


阅读 306

收藏
2020-07-28

共1个答案

一尘不染

std::remove_if(或std::erase)通过重新分配范围成员的值来工作。它不了解如何std::set组织数据,或如何从内部树数据结构中删除节点。确实,如果没有set对象本身,仅使用对节点的引用是不可能的。

标准算法设计为具有透明(或至少始终易于记忆)的计算复杂性。set由于需要重新平衡树,因此有选择地从a中删除元素的函数为O(N log
N),这比循环调用更好my_set.remove()。因此,该标准未提供它,而这正是您需要编写的。

另一方面,天真地手工编码的循环(一个接一个地删除项)vector将是O(N ^
2),而是std::remove_ifO(N)。因此,在这种情况下,图书馆确实提供了切实的利益。

典型的循环(C ++ 03样式):

for ( set_t::iterator i = my_set.begin(); i != my_set.end(); ) {
    if ( condition ) {
        my_set.erase( i ++ ); // strict C++03
        // i = my_set.erase( i ); // more modern, typically accepted as C++03
    } else {
        ++ i; // do not include ++ i inside for ( )
    }
}

编辑(4年后!):i ++在那里看起来可疑。如果在后增量运算符可以更新它之前使它erase无效怎么i办?不过,这很好,因为它是重载operator++而不是内置的运算符。该函数安全地i就地更新,
然后 返回其原始值的副本。

2020-07-28