2

I have a list list<x> bar and an array of iterators list<x>::iterator foo[100] initialized all elements with bar.end().

I want to store pointers in foo to some elements in bar while I'm going to erase, insert and push_back elements into bar. For element insertion I have to check if a position in foo is empty or not:

if (foo[my_number] != bar.end())
  //do something 1
else
  //do something 2

I receive an error only in case the foo[my_number] is already pointing to a bar element. The if is true I got this error (if false, no problem):

Debug Assertion Failed!

Program: C:\Windows\system32\MSVCP120D.dll
File: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\list
Line: 289

Expression: list iterators incompatible

I read here that after insertion the bar.end() is not the same as before. However, my code doesn't fail if I push back elements and compare a bar.end and foo[k] = end. But fails to compare bar.end to foo[k] = bar.begin() + p (this bar element exist).

What am I missing? How can I overcome this problem? Should I re-actualize foo after I inserted elements?

Community
  • 1
  • 1
Elod
  • 499
  • 9
  • 25
  • 3
    It sounds like you are trying to access an iterator that has been invalidated. Can you show an [mcve]? – NathanOliver Apr 08 '16 at 12:22
  • 5
    Iterators should be used for iteration. They have their syntax in order to enable the treatment of pointers as iterators, not the other way around. Using iterators as pointers is usually a bad idea. – molbdnilo Apr 08 '16 at 12:25
  • 1
    If you erased the element the iterator is pointing to you may have invalidated the iterator. – Rob Apr 08 '16 at 12:32
  • If I erase and element than I change the iterator too. How can I substitute the iterator array with a pointer array, that point to a list element and I can still navigate back and forth via the pointer? – Elod Apr 08 '16 at 12:38
  • working on the min working example, but in this case fails in the other case, when the `foo[i]` point to the end. – Elod Apr 08 '16 at 12:57

2 Answers2

2

insert or push_back operation in std::list does not invalidate iterators or references. erase invalidates iterators (and references) to the erased elements. The problem is caused by that you use iterator to erased element, after erase (or before), you should update this element iterator also in your array - preferable to end iterator.

The problem is that you should first find it, so before erase you might need to search it. How to you plan to keep synchronized your array and list?

Below is some example what you can and should not do:

  std::list<int> lst;
  std::vector<std::list<int>::iterator> arr;

  // Init arr with end() iterator
  arr.push_back(lst.end());

  // Add new list element
  lst.push_back(0);

  // Remember where it is in arr
  arr[0] = lst.begin();

  // Compare it.
  if ( arr[0] == lst.begin())
  {
    std::cout << "this is OK!\n";
  }

  lst.push_back(0);

  if (arr[0] == lst.begin())
  {
    std::cout << "this is still OK!\n";
  }

  lst.erase(lst.begin());
  //arr[0] = lst.end(); - without this, "list iterators incompatible" is issued by VS below
  if (arr[0] == lst.begin())
  {
    // list iterators incompatible
    std::cout << "This is WRONG!\n";
  }
marcinj
  • 48,511
  • 9
  • 79
  • 100
2

Erasing an element from a std::list invalidates iterators pointing to it (see here). So if you do erase from bar, be sure to remove the corresponding iterators from foo. All other std::list operations are supposed to keep existing iterators valid.

The link you found points to a question about std::vector which behaves differently with regard to iterator invalidation.