C++ 从STL列表中删除项目

C++ 从STL列表中删除项目,c++,stl,C++,Stl,我想做一个函数,如果项目符合某个条件,它可以将项目从一个STL列表移动到另一个STL列表 此代码不是执行此操作的方法。迭代器很可能会被erase()函数失效并导致问题: for(std::list<MyClass>::iterator it = myList.begin(); it != myList.end(); it++) { if(myCondition(*it)) { myOtherList.push_back(*it); myList.erase(i

我想做一个函数,如果项目符合某个条件,它可以将项目从一个STL列表移动到另一个STL列表

此代码不是执行此操作的方法。迭代器很可能会被erase()函数失效并导致问题:

for(std::list<MyClass>::iterator it = myList.begin(); it != myList.end(); it++)
{
  if(myCondition(*it))
  {
    myOtherList.push_back(*it);
    myList.erase(it);
  }
}
for(std::list::iterator it=myList.begin();it!=myList.end();it++)
{
if(myCondition(*it))
{
myOtherList.向后推(*it);
删除(它);
}
}
那么有人能提出更好的方法吗?

另一种尝试:

for(std::list<MyClass>::iterator it = myList.begin(); it != myList.end; ) {
    std::list<MyClass>::iterator eraseiter = it;
    ++it;
    if(myCondition(*eraseiter)) {
        myOtherList.push_back(*eraseiter);
        myList.erase(eraseiter);
    }
}
for(std::list::iterator it=myList.begin();it!=myList.end;){
std::list::iterator eraseiter=it;
++它;
if(myCondition(*橡皮擦)){
myOtherList.向后推(*橡皮擦);
我的列表。擦除(橡皮擦);
}
}
擦除
指向已擦除元素后的元素:

std::list<MyClass>::iterator it = myList.begin();
while (it != myList.end())
{
  if(myCondition(*it))
  {
    myOtherList.push_back(*it);
    it = myList.erase(it);
  }
  else
  {
    ++it;
  }
}
std::list::iterator it=myList.begin();
while(it!=myList.end())
{
if(myCondition(*it))
{
myOtherList.向后推(*it);
它=我的列表。删除(它);
}
其他的
{
++它;
}
}
解决方案1 第二种方法使用STL实现算法。我个人认为它比第一个解决方案更具可读性,但它有两个缺点:首先,它需要输入容器使用更强大的双向迭代器,而不是我们在第一个解决方案中使用的前向迭代器。其次,这可能是您的问题,也可能不是您的问题,容器的顺序不能保证与调用
std::partition()
之前相同。如果希望保持顺序,请将该调用替换为对
std::stable_partition()
的调用
std::stable_partition()
可能稍微慢一点,但它的运行时复杂性与
std::partition()
相同

任意一种方法:调用函数
list::迭代器p=move_if(l1.begin(),l1.end(),
背面插入器(l2),
bind2nd(less(),3));
最后发言 在编写代码时,我遇到了一个难题:
move\u if()
算法应该返回什么?一方面,算法应该返回一个迭代器,指向输入容器的新结束位置,这样调用者就可以使用erase-remove习惯用法来收缩容器。但另一方面,算法应该返回结果容器末尾的位置,因为否则调用方查找结果容器的代价可能会很高。在第一种解决方案中,当算法结束时,
结果
迭代器指向此位置,而在第二种解决方案中,
std::copy()
返回的迭代器指向此位置。我可以返回一对迭代器,但为了简化操作,我只返回其中一个迭代器。

template
template <typename ForwardIterator, typename OutputIterator, typename Predicate>
void splice_if(ForwardIterator begin, ForwardIterator end, OutputIterator out, Predicate pred)
{
    ForwardIterator it = begin;
    while( it != end )
    {
        if( pred(*it) )
        {
            *begin++ = *out++ = *it;
        }
        ++it;
    }
    return begin;
}

myList.erase( 
    splice_if( myList.begin(), myList.end(), back_inserter(myOutputList),
        myCondition
    ),
    myList.end()
)
如果(ForwardIterator begin、ForwardIterator end、OutputIterator out、谓词pred)无效 { ForwardIterator it=begin; while(it!=结束) { if(pred(*it)) { *开始+++=*输出+++=*它; } ++它; } 返回开始; } 删除( 拼接if(myList.begin()、myList.end()、back_插入器(myOutputList), 霉菌病 ), myList.end() )
STL列表有一个有趣的功能:使用
splice()
方法可以将元素从一个列表破坏性地移动到另一个列表

splice()
以恒定时间运行,不复制元素或执行任何免费存储分配/解除分配。请注意,两个列表必须是相同的类型,并且它们必须是单独的列表实例(而不是对同一列表的两个引用)

下面是一个如何使用
splice()
的示例:

for(std::list::iterator it=myList.begin();it!=myList.end();){
if(myCondition(*it)){
std::list::迭代器oldIt=it++;
拼接(myOtherList.end(),myList,oldIt);
}否则{
++它;
}
}
std::list::迭代器endMatching=
分区(myList.begin()、myList.end()、myCondition);
拼接(myOtherList.begin(),myList,endMatching,myList.end());
请注意,partition()为您提供了足够的空间来区分匹配对象和非匹配对象。 (然而,列表::splice()很便宜)

请参见以下代码,该代码来自

#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
CPred类:公共一元函数
{
公众:
CPred(常量字符串和arString)
:mString(arString)
{
}
布尔运算符()(常量字符串和arString)常量
{
返回(arString.find(mString)=std::string::npos);
}
私人:
字符串mString;
};
int main()
{
列出字符串;
字符串。推回(“213”);
字符串。推回(“145”);
字符串。推回(“ABC”);
字符串。推回(“167”);
字符串。推回(“DEF”);

你的意思是说remove_if?另外,myList.erase会引起问题,不是吗?否则,这就是我要发布的内容。=]我通常使用erase(it++),而不是依赖于erase的返回值,因为其他STL容器并不总是返回更新的迭代器。@haggai_e:标准要求erase()方法返回相关的迭代器。不遵循此方法的实现不符合标准,应避免使用。@haggai_e:每个STL容器都返回一个更新的迭代器。另一方面,您的++技巧不能保证适用于所有迭代器。(例如,在向量中,它将无效,因此您将无法增加它)@wilhemltell,@jalf:not true.std::map和其他关联容器类从erase函数返回void。但是,任何序列都会从erase返回以下迭代器。不起作用。首先,如果您决定使用迭代器,则无法收缩列表。其次,您无法访问算法内部的myList。
template<typename Bidi, typename Out, typename Operation>
Bidi move_if(Bidi first, Bidi last, Out result, Operation op)
{
    Bidi new_end = partition(first, last, not1(op));
    copy(new_end, last, result);
    return new_end;
}
list<int>::iterator p = move_if(l1.begin(), l1.end(),
                                back_inserter(l2),
                                bind2nd(less<int>(), 3));
template <typename ForwardIterator, typename OutputIterator, typename Predicate>
void splice_if(ForwardIterator begin, ForwardIterator end, OutputIterator out, Predicate pred)
{
    ForwardIterator it = begin;
    while( it != end )
    {
        if( pred(*it) )
        {
            *begin++ = *out++ = *it;
        }
        ++it;
    }
    return begin;
}

myList.erase( 
    splice_if( myList.begin(), myList.end(), back_inserter(myOutputList),
        myCondition
    ),
    myList.end()
)
for(std::list<MyClass>::iterator it = myList.begin(); it != myList.end(); ) {
    if(myCondition(*it)) {
        std::list<MyClass>::iterator oldIt = it++;
        myOtherList.splice(myOtherList.end(), myList, oldIt);
    } else {
        ++it;
    }
}
std::list<MyClass>::iterator endMatching =
    partition(myList.begin(), myList.end(), myCondition);
myOtherList.splice(myOtherList.begin(), myList, endMatching, myList.end());
#include <iostream>
#include <iterator>
#include <list>
#include <string>
#include <algorithm>
#include <functional>

using namespace std;

class CPred : public unary_function<string, bool>
{
public:
        CPred(const string& arString)
                :mString(arString)
        {
        }

        bool operator()(const string& arString) const
        {
                return (arString.find(mString) == std::string::npos);
        }
private:
        string mString;
};

int main()
{
        list<string> Strings;

        Strings.push_back("213");
        Strings.push_back("145");
        Strings.push_back("ABC");
        Strings.push_back("167");
        Strings.push_back("DEF");

        cout << "Original list" << endl;
        copy(Strings.begin(), Strings.end(),ostream_iterator<string>(cout,"\n"));

        CPred Pred("1");

        // Linear. Exactly last - first applications of pred, and at most (last - first)/2 swaps. 
        list<string>::iterator end1 =
        partition(Strings.begin(), Strings.end(), Pred);

        list<string> NotMatching;

        // This function is constant time. 
        NotMatching.splice(NotMatching.begin(),Strings, Strings.begin(), end1); 

        cout << "Elements matching with 1" << endl;
        copy(Strings.begin(), Strings.end(), ostream_iterator<string>(cout,"\n"));

        cout << "Elements not matching with 1" << endl;
        copy(NotMatching.begin(), NotMatching.end(), ostream_iterator<string>(cout,"\n"));

        return 0;
}