【问题标题】:iterator validity ,after erase() call in std::set迭代器有效性,在 std::set 中的 erase() 调用之后
【发布时间】:2010-12-10 19:55:56
【问题描述】:

在 std::set invalidate iterator 中进行擦除调用吗?正如我在最后一行的第 5 名以下所做的那样..? 如果是的话,从集合中删除所有元素的更好方法是什么

class classA
{
public:
    classA(){};
    ~classA(){};
};
struct structB
{
};

typedef std::set <classA*, structB> SETTYPE;        
typedef std::map <int, SETTYPE>MAPTYPE;

int __cdecl wmain (int argc, wchar_t* pArgs[])
{
    MAPTYPE mapObj; 
    /*
      ...
      ..   Some Operation Here
      ...
      */
    for (MAPTYPE::iterator itr1=mapObj.begin(); itr1!=mapObj.end(); itr1++) 
    {       
        SETTYPE li=(*itr1).second;
        for (SETTYPE::iterator itr2=li.begin();itr2!=li.end();itr2++) 
        {
            classA *lt=(classA*)(*itr2);
            li.erase(itr2); 
            delete lt; // Does it invalidate Iterator ?
        }
    }
}

【问题讨论】:

  • typedef std::set SETTYPE;我不确定您为什么将 StructB 作为第二个模板参数提供给 std::set。 std::set 只保存一个值(set 没有 key 和 map 一样),第二个模板参数用于为 set 提供比较函子(默认为 std::less)

标签: c++ stl set


【解决方案1】:

由于您显然只是删除了集合中的每个元素,因此您可以这样做:

    for (SETTYPE::iterator itr2=li.begin();itr2!=li.end();itr2++) 
    {
            classA *lt=(classA*)(*itr2);
            delete lt;
    }
    li.clear(); // clear the elements

【讨论】:

    【解决方案2】:

    从标准 23.1.2

    插入成员不应影响迭代器和对容器的引用的有效性,而擦除成员应仅使迭代器和对被擦除元素的引用无效。

    编辑

    在您的情况下,itr2 在擦除后无效,因此递增它会导致未定义的行为。在这种情况下你可以按照 reko_t 的建议,一般来说,你可以试试这个:

    for (SETTYPE::iterator itr2=li.begin();itr2!=li.end();) 
    {
        classA *lt=(classA*)(*itr2);
        li.erase(itr2++); 
        delete lt;
    }
    

    这将增加迭代器之前从集合中删除它的前一个值。
    顺便提一句。 itr2 没有被delete lt; 失效,而是被li.erase(itr2); 失效

    【讨论】:

    • 既然这回答了我的谷歌“是否设置擦除无效迭代器”,这是我最喜欢的答案
    • 我最喜欢的答案也是!
    【解决方案3】:

    删除没问题。

    问题是您删除了 - 从而使 - itr2 无效,但将其用于循环迭代。

    i.a.w.第一次擦除后,++itr2 的结果未定义。

    我在这种情况下使用的模式是这样的:

    while(itr2 != end())
    {
       iterator toDelete = itr2;
       ++itr2;   // increment before erasing!
       container.erase(toDelete);
    }
    

    一些非标准的 STL 实现有擦除返回下一个迭代器,所以你可以这样做:

    while(itr2 != end())
       itr2 = container.erase();
    

    不过,这不是便携式的。


    set&lt;A*,B&gt; 很奇怪,不过 - 在标准 impl 中,B 是比较器。

    【讨论】:

      猜你喜欢
      • 2017-04-15
      • 1970-01-01
      • 2021-09-25
      • 2022-07-18
      • 2012-09-13
      • 1970-01-01
      • 2018-01-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多