我有一组字符串:
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_if用std::set?我是否应该做其他事情,例如,set::find()随后的几次迭代set::erase()?
std::string
std::remove_if
std::set
set::find()
set::erase()
std::remove_if(或std::erase)通过重新分配范围成员的值来工作。它不了解如何std::set组织数据,或如何从内部树数据结构中删除节点。确实,如果没有set对象本身,仅使用对节点的引用是不可能的。
std::erase
set
标准算法设计为具有透明(或至少始终易于记忆)的计算复杂性。set由于需要重新平衡树,因此有选择地从a中删除元素的函数为O(N log N),这比循环调用更好my_set.remove()。因此,该标准未提供它,而这正是您需要编写的。
my_set.remove()
另一方面,天真地手工编码的循环(一个接一个地删除项)vector将是O(N ^ 2),而是std::remove_ifO(N)。因此,在这种情况下,图书馆确实提供了切实的利益。
vector
典型的循环(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就地更新, 然后 返回其原始值的副本。
i ++
erase
i
operator++