tags:

views:

1304

answers:

4

Do erase call in std::set invalidate iterator ? As i have done below 5th from last line..? if yes what is better way to erase all elements from set

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 ?
     }
    }
}
+2  A: 

Since you are just apparently deleting every element of the set, you could just do:

    for (SETTYPE::iterator itr2=li.begin();itr2!=li.end();itr2++) 
    {
            classA *lt=(classA*)(*itr2);
            delete lt;
    }
    li.clear(); // clear the elements
reko_t
thx reko_t , this solves my problem
sat
+3  A: 

From standard 23.1.2

The insert members shall not affect the validity of iterators and references to the container, and the erase members shall invalidate only iterators and references to the erased elements.

EDIT

In your case itr2 is invalidated after erasing so incrementing it causes undefined behaviour. In this case you can follow reko_t advice, in general, you can try this:

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

which will increment iterator before removing it's previous value from set.
BTW. itr2 is not invalidated by delete lt;, but by li.erase(itr2);

Tadeusz Kopec
A: 

The delete is ok.

The problem is that you erase - and thus invalidate - itr2, but use it for loop iteration.

i.a.w. after the first erase, the ++itr2 has undefined results.

The pattern I use in this situation is this:

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

Some non-standard STL impls have erase return the next iterator, so you could do:

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

that's not portable, though.


the set<A*,B> is strange, though - in a standard impl, B would be the comparator.

peterchen
A: 

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

i think this is equal with for (SETTYPE::iterator itr2=li.begin();itr2!=li.end();itr2++) { classA lt=(classA)(*itr2); li.erase(itr2); delete lt; }

can anyone give some explanation? thank you.

Raymond