我的 vector::erase 有什么问题吗?

发布于 2025-01-02 00:57:08 字数 889 浏览 7 评论 0原文

我的程序中有两个向量,分别称为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中删除一系列元素;

我没有使用 C++11。

I have two vector<T> in my program, called active and non_active respectively. This refers to the objects it contains, as to whether they are in use or not.

I have some code that loops the active vector and checks for any objects that might have gone non active. I add these to a temp_list inside the loop.

Then after the loop, I take my temp_list and do non_active.insert of all elements in the temp_list.

After that, I do call erase on my active vector and pass it the temp_list to erase.

For some reason, however, the erase crashes.

This is the code:

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

I get this assertion:

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

I've looked online and seen that there is a erase-remove idiom, however not sure how I'd apply that to a removing a range of elements from a vector<T>

I'm not using C++11.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

笔芯 2025-01-09 00:57:08

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 和带有 find 成员函数调用 set 的 std::find_if ,性能应该是可以接受的。

erase expects a range of iterators passed to it that lie within the current vector. You cannot pass iterators obtained from a different vector to erase.

Here is a possible, but inefficient, C++11 solution supported by lambdas:

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

And here is the equivalent C++03 solution without the lambda:

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

If you replace temp_list with a std::set and the std::find_if with a find member function call on the set, the performance should be acceptable.

巾帼英雄 2025-01-09 00:57:08

擦除方法旨在接受同一容器对象的迭代器。您试图将迭代器传递给 temp_list 以用于从活动中删除元素,但出于充分的原因,这是不允许的,因为序列的范围擦除方法旨在指定要删除的序列中的范围。迭代器按该顺序排列很重要,否则我们将指定要擦除的值范围,而不是同一容器内的范围,这是一种成本更高的操作。

您尝试执行的逻辑类型向我表明,一组或列表可能更适合该目的。也就是说,您尝试从容器中间删除匹配特定条件的各种元素并将它们转移到另一个容器,并且您可以通过这种方式消除对 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());

有关此内容的更多信息可以在“擦除删除习惯用法”主题下找到,并且您可能需要谓词函数对象,具体取决于确定对象是否不再处于活动状态所需的外部状态。

The erase method is intended to accept iterators to the same container object. You're trying to pass in iterators to temp_list to use to erase elements from active which is not allowed for good reasons, as a Sequence's range erase method is intended to specify a range in that Sequence to remove. It's important that the iterators are in that sequence because otherwise we're specifying a range of values to erase rather than a range within the same container which is a much more costly operation.

The type of logic you're trying to perform suggests to me that a set or list might be better suited for the purpose. That is, you're trying to erase various elements from the middle of a container that match a certain condition and transfer them to another container, and you could eliminate the need for temp_list this way.

With list, for example, it could be as easy as this:

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

However, sometimes vector can outperform these solutions, and maybe you have need for vector for other reasons (like ensuring contiguous memory). In that case, std::remove_if is your best bet.

Example:

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

More info on this can be found under the topic, 'erase-remove idiom' and you may need predicate function objects depending on what external states are required to determine if an object is no longer active.

梦断已成空 2025-01-09 00:57:08

实际上,您可以使擦除/删除习惯用法适用于您的情况。您只需将值移至另一个容器之前 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 来使代码更短,而不是担心输出等问题。)

You can actually make the erase/remove idiom usable for your case. You just need to move the value over to the other container before std::remove_if possibly shuffles it around: in the predicate.

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. (I directly used bools to make the code shorter, not bothering with output and the likes.)

一口甜 2025-01-09 00:57:08

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

The function std::vector::erase requires the iterators to be iterators into this vector, but you are passing iterators from temp_list. You cannot erase elements from a container that are in a completely different container.

意中人 2025-01-09 00:57:08
active.erase(temp_list.begin(), temp_list.end());

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

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

You try to erase elements from one list, but you use iterators for second list. First list iterators aren't the same, like in second list.

我们的影子 2025-01-09 00:57:08

我想建议这是应该使用 std::list 的示例。您可以将一个列表中的成员拼接到另一个列表中。请参阅 std::list::splice() 了解这一点。

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

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

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

我现在将在这里编写一个算法来运行一个集合,如果存在条件,它将影响 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() );

I would like to suggest that this is an example of where std::list should be used. You can splice members from one list to another. Look at std::list::splice()for this.

Do you need random access? If not then you don't need a std::vector.

Note that with list, when you splice, your iterators, and references to the objects in the list remain valid.

If you don't mind making the implementation "intrusive", your objects can contain their own iterator value, so they know where they are. Then when they change state, they can automate their own "moving" from one list to the other, and you don't need to transverse the whole list for them. (If you want this sweep to happen later, you can get them to "register" themselves for later moving).

I will write an algorithm here now to run through one collection and if a condition exists, it will effect a std::remove_if but at the same time will copy the element into your "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;
}

This is a bit like std::remove_if but will copy the ones being removed into an alternative collection. You would invoke it like this (for a vector) where isInactive is a valid predicate that indicates it should be moved.

active.erase( copy_and_remove_if( active.begin(), active.end(), std::back_inserter(inactive), isInactive ), active.end() );
注定孤独终老 2025-01-09 00:57:08

您传递给 erase() 的迭代器应指向 vector 本身;这个断言告诉你他们没有。此版本的erase() 用于擦除向量 中的某个范围。

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

The iterators you pass to erase() should point into the vector itself; the assertion is telling you that they don't. This version of erase() is for erasing a range out of the vector.

You need to iterate over temp_list yourself and call active.erase() on the result of dereferencing the iterator at each step.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文