2

I have list with objects. I get some items from that list and do something with items. If work is done without errors i wish to delete these items from list. After that, on erase I get exception of incompatible iterator. I understand that tmp is different list. But how to solve this problem?

#include <list>

class A
{
public:
    A(int i):i_(i){}
private:
    int i_;
};

int _tmain(int argc, _TCHAR* argv[])
{
    std::list<A> list;
    A a(1), b(2), c(3);
    list.push_back(a);
    list.push_back(b);
    list.push_back(c);

    std::list<A> tmp;
    tmp.insert(tmp.end(), list.begin(), list.end());
    // do something with tmp
    // if all is ok, then erase what is done
    list.erase(tmp.begin(), tmp.end());

    return 0;
}

tmp.Insert not always get full list. It can copy part of list, so i don't want clear whole list.

userbb
  • 2,148
  • 5
  • 30
  • 53

6 Answers6

6

You can't erase from one list using iterators from another list. An iterator "points" to some node in a list. Its pointing to something in a specific list. When you copy those things into another list, you have two lists with two sets of nodes now. Your iterator points to only one of those copies, not to both.

In the program as it is, the std::list destructor will cause your list to cleanup, so you don't even need to do an explicit clear.

As others have said, you can use clear to blow away the contents of the list. But I'm not 100% sure thats what you mean to do. Do you mean to erase all the contents of list that are also in tmp? If that's the case, then you may wish to use remove_if with a predicate

 class CIsContainedInOtherList
 { 
 private:
     const std::list<int>& m_list;
 public:
      CIsContainedInOtherList(const std::list<int>& list);

      // return true if val is in m_list
      bool operator()(const int& val) const
      {
          std::list<int>::const_iterator iter 
             = std::find(m_list.begin(), m_list.end(), val);
          return (iter != m_list.end())
      }
 }

 int main()
 {
      ...
      CIsContainedInOtherList ifInOtherList(tmp);
      std::list<int>::iterator iter = 
              remove_if(list.begin(), list.end(), ifInOtherList);
      // remove everything that matched the predicate
      list.erase(iter, list.end());
 }
Doug T.
  • 64,223
  • 27
  • 138
  • 202
  • This comment makes perfect sense, but why does this code compile and run fine under g++ 4.5? – iksemyonov May 03 '11 at 12:48
  • @Semen: because the compiler only checks if the iterators have the correct type for the operation, which they do. – Fred Foo May 03 '11 at 12:50
  • Well yes, it should compile and it does. But why does it run without raising any exceptions or somesuch? – iksemyonov May 03 '11 at 12:52
  • 1
    @Semen, part of the reason is that libraries enforce different amounts of checking. The std cops out on things like this by just saying it causes "undefined behavior". But its not much of a cop out, libraries such as Microsoft's allow you to turn on very strict STL checking but the performance hit is terrible. See here: http://askldjd.wordpress.com/2009/09/13/stl-performance-comparison-vc71-vc90-and-stlport/ – Doug T. May 03 '11 at 13:02
  • What about remember range of iterators of list. Copy range to tmp. And if all is ok remove membered range from list? – userbb May 03 '11 at 13:13
  • http://stackoverflow.com/questions/5869573/stdlist-erase-incompatible-iterator/5870123#5870123 – userbb May 03 '11 at 13:55
0

I think you wanna clear your list, use, list.clear() Also, in your code:

list.erase(tmp.begin(), tmp.end());

is wrong! I think you meant:

list.erase(list.begin(), list.end());
atoMerz
  • 7,534
  • 16
  • 61
  • 101
0
  list.erase(tmp.begin(), tmp.end());
//^^^^

Typo!

I think you wanted to type:

  tmp.erase(tmp.begin(), tmp.end());
//^^^^

The reason why you get error, because you cannot delete elements from one list using iterator range obtained from another list. Iterator obtained from one list is unreachable from iterator obtained from another list.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • I don't want clear tmp. I need to clear `list` if all operations are done on `tmp` which is subset of list on i can operate. But clear only elements that are in `tmp` – userbb May 03 '11 at 13:27
0

You're trying to erase from list using iterators for tmp - that makes no sense, what would be erased?

 list.erase(list.begin(), list.end());

or, just list.clear();

Erik
  • 88,732
  • 13
  • 198
  • 189
0

I have idea with using boost::iterator_range. Its saves range for later delete. Is it ok?

typedef std::list<A>::iterator AIter;

std::list<A> tmp;
boost::iterator_range<AIter>  range(list.begin(), list.end());
tmp.insert(tmp.end(), range.begin(), range.end());

list.erase(range.begin(), range.end());
userbb
  • 2,148
  • 5
  • 30
  • 53
0

It sounds like your problem is similar to the one in Can you remove elements from a std::list while iterating through it?. You could probably use a similar solution.

Community
  • 1
  • 1
AShelly
  • 34,686
  • 15
  • 91
  • 152