简体   繁体   中英

Vector Iterators Incompatible

I have a class with a std::vector data member eg

class foo{
public:

const std::vector<int> getVec(){return myVec;} //other stuff omitted

private:
std::vector<int> myVec;

};

Now at some part of my main code I am trying to iterate through the vector like this:

std::vector<int>::const_iterator i = myFoo.getVec().begin();
while( i != myFoo.getVec().end())
{
   //do stuff
   ++i;
}

The moment I reach this loop, I get the aforementioned error.

The reason you are getting this, is that the iterators are from two (or more) different copies of myVec. You are returning a copy of the vector with each call to myFoo.getVec() . So the iterators are incompatible .

Some solutions:

Return a const reference to the std::vector<int> :

const std::vector<int> & getVec(){return myVec;} //other stuff omitted

Another solution, probably preferable would be to get a local copy of the vector and use this to get your iterators:

const std::vector<int> myCopy = myFoo.getVec();
std::vector<int>::const_iterator i = myCopy.begin();
while(i != myCopy.end())
{
  //do stuff
  ++i;
}

Also +1 for not using namespace std;

You are returning a copy of the vector. Because you are returning by value - your call to begin() and end() are for completely different vectors. You need to return a const & to it.

const std::vector<int> &getVec(){return myVec;}

I would do this slightly differently though. I'd make the class act a little like a standard container

class Data
{
   public:
      typedef std::vector<int>::const_iterator const_iterator;

      const_iterator begin() const { return myVec.begin(); }
      const_iterator end() const { return myVec.end(); }
};

Data::const_iterator i=myFoo.begin();

while(i != myFoo.end())
{
//
}

Another cause of the MSVC STL debug assertion "vector iterators incompatible" is operating on an invalidated iterator.

Ie v.erase(i) , and then compare i != v.end() the erase invalidates i and so it cannot be used in a comparison.

well, I don't think vector copy could be the only cause, that seems to be too obivious to me.

in my case I just find that corrupted stack, heap, uninteneded changes could also result in this failure, and it will in fact hiding the underlying reason. in my case, I changed to use indexer to iterate through and find the root cause.

Another reason why this assert can trigger is if you would allocate "foo" with 'malloc' instead of 'new', effectively skipping the constructor(s).

It's unlikely to happen to a project developed from scratch in C++, but when converting plain-C code to C++ (replacing a static array[] in some struct with an stl-vector) you might just not realise that dynamic instances of said struct (and the members inside) are not going to have their constructor called - unless you also change 'malloc' to 'new'.

The problem is that you always return another copy of the vector. Use a reference:

const std::vector<int>& getVec(){return myVec;} //other stuff omitted

You are making a constant copy of the member vector, not accessing the member vector.

Change this:

const std::vector<int> getVec(){return myVec;} //other stuff omitted

to this:

const std::vector<int> & getVec(){return myVec;} //other stuff omitted

To go a little deeper, the iterator you get from this statement:

std::vector<int>::const_iterator i = myFoo.getVec().begin();

is an iterator to the temporary copy of your vector, which goes away after that statement executes, invalidating the iterator.

Change

const std::vector<int> getVec(){return myVec;}

to

const std::vector<int>& getVec(){return myVec;}

Your getVec() function returns a deep copy of the member vector, so the two getVec() calls you make to retrieve iterators get iterators to different containers. That is, you can't reach getVec().end() from a separate getVec().begin() iterator without invoking undefined behavior.

You can solve this in two ways:

1) Have getVec return a const reference (that is, const std::vector&) (preferred) or...

2) Replace the two getVec() calls with one and save the result to a std::vector variable. Then, use that variable for both calls to begin() and end(). Eg:

std::vector<int> v = myFoo.getVec();
std::vector<int>::const_iterator b = v.begin();
std::vector<int>::const_iterator e = v.end();

Because you are returning by value - your call to begin() and end() are for completely different vectors. You need to return a const & to it

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM