我的vector <t> :: erase here?</t>有什么问题

时间:2012-02-01 14:08:02

标签: c++ vector erase

我的程序中有两个vector<T>,分别称为activenon_active。这是指它包含的对象,以及它们是否在使用中。

我有一些代码循环active向量并检查可能已经非活动的任何对象。我将这些添加到循环内的temp_list

然后循环之后,我将temp_listnon_active.insert中的所有元素进行temp_list

之后,我会在erase向量上拨打active并将temp_list传递给要删除。

但出于某种原因,erase崩溃了。

这是代码:

non_active.insert(non_active.begin(), temp_list.begin(), temp_list.end());
active.erase(temp_list.begin(), temp_list.end());

我得到了这个断言:

Expression:("_Pvector == NULL || (((_Myvec*)_Pvector)->_Myfirst <= _Ptr && _Ptr <= ((_Myvect*)_Pvector)->_Mylast)",0)

我看过网上看到有一个删除删除的习惯用法,但不确定我是如何将其应用于删除vector<T>

中的一系列元素

我没有使用C ++ 11。

7 个答案:

答案 0 :(得分:8)

erase期望传递给它的一系列迭代器位于当前向量中。您不能将从不同向量获取的迭代器传递给erase

这是lambda支持的一种可能但效率低下的C ++ 11解决方案:

active.erase(std::remove_if(active.begin(), active.end(), [](const T& x)
{
    return std::find(temp_list.begin(), temp_list.end(), x) != temp_list.end();
}), active.end());

这是没有lambda的等效C ++ 03解决方案:

template<typename Container>
class element_of
{
    Container& container;

    element_of(Container& container) : container(container) {}

public:

    template<typename T>
    bool operator()(const T& x) const
    {
        return std::find(container.begin(), container.end(), x)
            != container.end();
    }
};

// ...

active.erase(std::remove_if(active.begin(), active.end(),
                            element_of<std::vector<T> >(temp_list)),
             active.end());

如果您使用temp_list替换std::set,并使用std::find_if成员函数调用find,则性能应该可以接受。

答案 1 :(得分:3)

erase方法旨在接受同一容器对象的迭代器。您正尝试将迭代器传递给temp_list以用于擦除活动中的元素,这是有充分理由不允许的,因为Sequence的范围擦除方法旨在指定要删除的序列中的范围。重要的是迭代器处于该序列中,因为否则我们指定要擦除的值范围而不是同一容器中的范围,这是一个成本高得多的操作。

您尝试执行的逻辑类型向我表明,集合或列表可能更适合此目的。也就是说,你试图从容器中间删除符合特定条件的各种元素并将它们转移到另一个容器,你可以用这种方式消除对temp_list的需求。

例如,使用列表,它可以像这样简单:

for (ActiveList::iterator it = active.begin(); it != active.end();)
{
    if (it->no_longer_active())
    {
        inactive.push_back(*it);
        it = active.erase(it);
    }
    else
        ++it;
}

然而,有时矢量可以胜过这些解决方案,也许你出于其他原因需要矢量(比如确保连续的内存)。在这种情况下,std :: remove_if是你最好的选择。

示例:

bool not_active(const YourObjectType& obj);
active_list.erase(
    remove_if(active_list.begin(), active_list.end(), not_active), 
    active_list.end());

有关这方面的更多信息可以在“擦除删除习惯用法”主题下找到,您可能需要谓词函数对象,具体取决于确定某个对象是否不再有效所需的外部状态。

答案 2 :(得分:3)

您实际上可以根据您的情况使用擦除/删除习惯用法。您只需将值移动到另一个容器,然后 std::remove_if可能会将其混乱:在谓词中。

template<class OutIt, class Pred>
struct copy_if_predicate{
  copy_if_predicate(OutIt dest, Pred p)
    : dest(dest), pred(p) {}

  template<class T>
  bool operator()(T const& v){
    if(pred(v)){
      *dest++ = v;
      return true;
    }
    return false;
  }

  OutIt dest;
  Pred pred;
};

template<class OutIt, class Pred>
copy_if_predicate<OutIt,Pred> copy_if_pred(OutIt dest, Pred pred){
  return copy_if_predicate<OutIt,Pred>(dest,pred);
}

Live example on Ideone.(我直接使用bool来缩短代码,而不是打扰输出等。)

答案 3 :(得分:2)

函数std::vector::erase要求迭代器成为此向量的迭代器,但是您要从temp_list传递迭代器。您无法从容器中删除完全不同容器中的元素。

答案 4 :(得分:1)

active.erase(temp_list.begin(), temp_list.end());

您尝试从一个列表中删除元素,但是您将迭代器用于第二个列表。第一个列表迭代器不一样,就像在第二个列表中一样。

答案 5 :(得分:1)

我想建议这是应该使用std::list的示例。您可以将成员从一个列表拼接到另一个列表。请查看std::list::splice()

您需要随机访问吗?如果没有,那么您不需要std::vector

请注意,对于list,在拼接时,迭代器和对列表中对象的引用仍然有效。

如果你不介意使实现“侵入”,你的对象可以包含它们自己的迭代器值,因此它们知道它们的位置。然后,当他们改变状态时,他们可以自动将他们自己的“移动”从一个列表移动到另一个列表,并且您不需要为它们横切整个列表。 (如果您希望稍后进行此扫描,您可以让它们“注册”自己以便以后移动)。

我现在在这里编写一个算法来运行一个集合,如果存在条件,它将影响std :: remove_if,但同时会将元素复制到“插入器”中。

 //fwd iterator must be writable
template< typename FwdIterator, typename InputIterator, typename Pred >
FwdIterator copy_and_remove_if( FwdIterator inp, FwdIterator end, InputIterator outp, Pred pred )
{
    for( FwdIterator test = inp; test != end; ++test )
    {
        if( pred(*test) ) // insert
        {
            *outp = *test;
            ++outp;
        }
        else // keep
        {
           if( test != inp )
           { 
              *inp = *test;
           }
           ++inp;
        }
   }
   return inp;
}

这有点像std::remove_if但会将要删除的内容复制到备用集合中。你可以这样调用它(对于一个向量),其中isInactive是一个有效的谓词,表明它应该被移动。

active.erase( copy_and_remove_if( active.begin(), active.end(), std::back_inserter(inactive), isInactive ), active.end() );

答案 6 :(得分:0)

传递给erase()的迭代器应该指向vector本身;断言告诉你他们没有。此版本的erase()用于删除vector之外的范围。

你需要自己迭代temp_list并在每一步取消引用迭代器的结果上调用active.erase()