原位删除元素的最佳方法

发布于 2024-07-11 03:42:17 字数 806 浏览 7 评论 0原文

我有一组要迭代的对象,但是我可能会在迭代期间决定现在需要删除其中一个(或多个)对象。

我的代码如下:

if( ! m_Container.empty() )
    {
        for(  typedefedcontainer::iterator it = m_Container.begin();
              it != m_Container.end(); 
              ++it  )
        {
            if( ! ( SomeFunction( (*it), "test", "TEST!", false ))  )
            {
            // If function returns false, delete object.
                m_Container.erase( it );
                AsyncResponseStore::iterator it = m_asyncResponses.begin();
            }

        }


    }

但是,当然,当我删除一个对象时,我收到一个错误:“映射/设置迭代器不可递增”。 有人可以建议更好的方法吗?

看: 如果在从开始到结束迭代时对地图元素调用擦除(),会发生什么?

I have a set of objects which I iterate through, however I may decide during the iteration that one (or more) of those objects now need to be deleted.

My code goes as follows:

if( ! m_Container.empty() )
    {
        for(  typedefedcontainer::iterator it = m_Container.begin();
              it != m_Container.end(); 
              ++it  )
        {
            if( ! ( SomeFunction( (*it), "test", "TEST!", false ))  )
            {
            // If function returns false, delete object.
                m_Container.erase( it );
                AsyncResponseStore::iterator it = m_asyncResponses.begin();
            }

        }


    }

But of course, when I erase an object I get an error : "Map / set iterator not incrementable". Can someone suggest a better way of doing this?

See:
What happens if you call erase() on a map element while iterating from begin to end?

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

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

发布评论

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

评论(3

我的黑色迷你裙 2024-07-18 03:42:17

这取决于容器。 列表容器通过从代表列表中下一项的擦除方法返回一个新的迭代器来支持枚举期间的删除。 地图不支持这个。

映射的一个简单方法是将要删除的项目累积在单独的列表中,然后在处理完映射后迭代该列表以从映射中删除项目。 这假设您可以将删除推迟到迭代完成。 如果没有,那么您别无选择,只能重新启动每次删除的迭代。

It depends on the container. The list container supports deletion during enumeration by returning a new iterator from the erase method that represents the next item in the list. map doesn't support this.

A simple method for map is to accumulate the items you want to erase in a separate list, and then iterate over that list when you have finished processing the map to erase the items from the map. This assumes that you can defer the deletion until the iteration has completed. If not then you have no choice but the restart the iteration for each deletion.

囍笑 2024-07-18 03:42:17

如果容器支持它(我怀疑你的不支持,但问题标题是通用的,所以这可能对其他人有用,如果不是你的话):

struct SomePredicate {
    bool operator()(typedefedcontainer::value_type thing) {
        return ! SomeFunction(thing, "test", "TEST", false);
    }
};

typedefedcontainer::iterator it;
it = std::remove_if(m_Container.begin(), m_Container.end(), SomePredicate());
m_Container.erase(it, m_Container.end());

m_Container 必须有一个擦除范围方法,其中包括任何序列或关联容器。 不过,它确实必须有一个可变迭代器,而且我刚刚注意到我最初误读了错误消息:它说“映射/设置迭代器不可递增”。 所以我猜你的容器是一张地图或一组。

请注意,最后三个可能是真正精彩的俏皮话,但这个边距太窄而无法包含它。

另外, SomePredicate 可以有一个带有参数的构造函数,用于将附加参数存储到 SomeFunction 中,因为在现实生活中我猜它们是非常量的。

如果您使用 boost:bind 构造函子,您实际上可以完全摆脱 SomePredicate。 那么你的一句台词就会变得非常庞大。

[编辑:罗布·沃克在他的回答中正确地指出了我在这里所做的一个假设,并且问题没有说明,即所有擦除都可以推迟到迭代和测试完成之后。 如果SomeFunction通过隐藏路由(例如全局,或者因为SomeFunction实际上是this的成员函数)访问m_Container,并且其结果取决于容器的内容,那么我的代码可能不等于提问者的代码。 但我认为我的代码是“除非有理由不这样做”默认值。]

If the container supports it (which I suspect yours doesn't, but the question title is generic so this may be useful to others if not you):

struct SomePredicate {
    bool operator()(typedefedcontainer::value_type thing) {
        return ! SomeFunction(thing, "test", "TEST", false);
    }
};

typedefedcontainer::iterator it;
it = std::remove_if(m_Container.begin(), m_Container.end(), SomePredicate());
m_Container.erase(it, m_Container.end());

m_Container must have an erase range method, which includes any Sequence or Associative Container. It does have to have a mutable iterator, though, and I just noticed that I originally misread the error message: it says "map / set iterator not incrementable". So I guess your container is a map or a set.

Note that the last three could be a truly marvellous one-liner, but this margin is too narrow to contain it.

Also that SomePredicate could have a constructor with parameters to store the additional parameters to SomeFunction, since in real life I guess they're non-constant.

You could actually get rid of SomePredicate entirely if you use boost:bind to construct the functor. Your one-liner would then be truly massive.

[Edit: Rob Walker correctly notes in his answer an assumption that I make here and that the question doesn't state, which is that all erasing can be deferred until after the iterate-and-test is done. If SomeFunction accesses m_Container by a hidden route (e.g. a global, or because SomeFunction is actually a member function of this), and its results depend on the contents of the container, then my code may not be equivalent to the questioner's code. But I think my code is the "unless there's a reason not to" default.]

爱的十字路口 2024-07-18 03:42:17

通过以下内容修复:

for(  typedefedcontainer::iterator it = m_Container.begin();
      it != m_Container.end(); 
        )
{
    if( ! ( SomeFunction( (*it), "test", "TEST!", false ))  )
    {
    // If function returns false, delete object.
        m_Container.erase( it++ );
    }
    else
    { 
        ++i;
    } 

}

删除元素时,指向该元素的所有指针都会失效。 因此,通过使用 it++ 我们可以绕过它。 感谢那些发表建议的人。

Fixed by the following:

for(  typedefedcontainer::iterator it = m_Container.begin();
      it != m_Container.end(); 
        )
{
    if( ! ( SomeFunction( (*it), "test", "TEST!", false ))  )
    {
    // If function returns false, delete object.
        m_Container.erase( it++ );
    }
    else
    { 
        ++i;
    } 

}

When an element is deleted, all pointers to it become invalidated. Therefore by using it++ we get around it. Thanks to those who posted suggestions.

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