43

I have a class with a std::vector data member e.g.

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.

Laurel
  • 5,965
  • 14
  • 31
  • 57
IG83
  • 555
  • 1
  • 4
  • 5

10 Answers10

76

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;

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
FailedDev
  • 26,680
  • 9
  • 53
  • 73
11

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())
{
//
}
Adrian Cornish
  • 23,227
  • 13
  • 61
  • 77
9

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

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

nmr
  • 16,625
  • 10
  • 53
  • 67
2

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.

zinking
  • 5,561
  • 5
  • 49
  • 81
2

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'.

kalmiya
  • 2,988
  • 30
  • 38
2

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
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
jdehaan
  • 19,700
  • 6
  • 57
  • 97
1

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.

Rob K
  • 8,757
  • 2
  • 32
  • 36
  • Slightly off-topic, but your for loop to do stuff should be in a member method of class foo. You generally shouldn't have things outside a class operating on the internal data of a class. – Rob K Dec 07 '11 at 20:01
  • 1
    And it's an invalidate iterator for a _different_ container. Two problems. – Lightness Races in Orbit Dec 07 '11 at 20:02
1

Change

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

to

const std::vector<int>& getVec(){return myVec;}
Igor
  • 26,650
  • 27
  • 89
  • 114
0

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

  • Hi, and welcome to Stack Overflow. Your answer, while it might be correct, is quite terse and difficult to understand. It would be useful if you could expand it; for example if you include some code which uses the change you recommend? – Vince Bowdren Aug 16 '16 at 12:05
  • This exact answer was also used in response to a since-deleted markov generated nonsense question and selected as the answer to said nonsense question. – user4581301 Aug 16 '16 at 15:55
0

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(). E.g:

std::vector<int> v = myFoo.getVec();
std::vector<int>::const_iterator b = v.begin();
std::vector<int>::const_iterator e = v.end();
Drew Hall
  • 28,429
  • 12
  • 61
  • 81