我的矢量有什么问题<T>::擦除这里?

What's wrong with my vector<T>::erase here?

本文关键字:gt 擦除 这里 lt 什么 问题 我的      更新时间:2023-10-16

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

我有一些代码可以循环active向量,并检查任何可能处于非活动状态的对象。我将这些添加到循环中的temp_list中。

然后循环之后,我取我的temp_list,对temp_list中的所有元素进行non_active.insert

之后,我在active向量上调用erase,并将其传递给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。

erase期望传递给它的迭代器范围位于当前向量内。不能将从其他向量获得的迭代器传递给erase

这里有一个可能的,但效率低下的,由lambdas支持的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());

这是一个没有λ的等价的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成员函数调用,则性能应该可以接受。

擦除方法旨在接受同一容器对象的迭代器。您正试图将迭代器传递到temp_list以用于从活动中擦除元素,这是有充分理由不允许的,因为Sequence的范围擦除方法旨在指定要删除的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;
}

然而,有时vector可以胜过这些解决方案,并且可能由于其他原因(如确保连续内存)而需要vector。在这种情况下,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());

有关这方面的更多信息可以在主题"删除习语"下找到,您可能需要谓词函数对象,这取决于确定对象是否不再活动所需的外部状态。

您实际上可以使擦除/删除习惯用法适用于您的情况。您只需要将值移动到另一个容器,然后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);
}

Ideone上的实例。(我直接使用了bool s来缩短代码,而不必考虑输出等。)

函数std::vector::erase要求迭代器是这个向量中的迭代器,但您正在从temp_list传递迭代器。不能从完全不同的容器中删除元素。

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

您试图从一个列表中删除元素,但对第二个列表使用迭代器。第一个列表迭代器与第二个列表不同。

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

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

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

如果您不介意让实现"具有侵入性",那么您的对象可以包含自己的迭代器值,这样它们就知道自己在哪里。然后,当他们改变状态时,他们可以自动从一个列表"移动"到另一个列表,而不需要为他们遍历整个列表。(如果您希望稍后进行此扫描,您可以让他们自己"注册"以便稍后移动)。

我现在将在这里编写一个算法来运行一个集合,如果条件存在,它将产生std::remove_if,但同时将元素复制到您的"inserter"中。

 //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() );

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

您需要自己对temp_list进行迭代,并在每一步对迭代器的解引用结果调用active.erase()