Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Vector Iterators Incompatible" when calculating distance between two iterators

I'm having an issue which I cannot quite find the cause of.

At a certain point in my code I'm returning the distance between two std::vector iterators, one being the result of an insert operation on a vector and the other pointing to the beginning of the vector. The idea is to return the index of the newly inserted object.

Everything works perfectly when I phrase the code like this

const_iterator (or auto) it = insert(object);
return it - begin();

However, if I try to make a one liner out of it

return insert(object) - begin();

I get the aforementioned "Vector Iterators Incompatible" assertion.

begin() is implemented as:

MyClass::iterator MyClass::begin()
{
  return m_container.begin();
}

and insert() is implemented as:

MyClass::iterator MyClass::insert(MyObject *object)
{
  if (object)
  {
    const_iterator it = std::lower_bound(begin(), end(), object, DereferencedLess<MyObject >());

    if (it == end() || *(*it) != *object)
      return m_container.insert(it, object);
  }

  return end();
}

Brief outline of the class:

MyClass {
  ...
  iterator  begin();
  const_iterator begin() const;
  iterator  insert(MyObject*);

  ...
  protected:
  std::vector<MyObject*> m_container;
}

and for completeness' sake

template<typename T>
struct DereferencedLess
{ inline bool operator()(const T *p1, const T *p2) const { return *p1 < *p2; } };

I would very much like to understand why the assertion happens. From what I can see the iterators are of the same type and both insert() and begin() are working on the same vector. All the necessary typedefs are in place as well.

like image 295
marcbf Avatar asked Mar 05 '23 09:03

marcbf


1 Answers

vector::insert invalidates the iterators. In expression insert(object) - begin() begin() can be called before or after insert. If it is called before than it is invalidated by insert(). Order of evaluation:

Order of evaluation of the operands of almost all C++ operators (including the order of evaluation of function arguments in a function-call expression and the order of evaluation of the subexpressions within any expression) is unspecified. The compiler can evaluate operands in any order, and may choose another order when the same expression is evaluated again.

Whereas when you do:

const_iterator (or auto) it = insert(object);
return it - begin();

begin() is called after insert() and hence returns a valid iterator.

like image 130
Maxim Egorushkin Avatar answered Apr 27 '23 00:04

Maxim Egorushkin