How can vector const_iterator go past vector end? - c++

I have the following code in an application that threw an access violation exception:
size_t CConnectionsDoc::get_active_connections( std::vector<CString> &conn )
{
CString temp;
size_t cnt = 0;
conn.clear();
if( initialized ) {
for( std::vector<ACTIVE_CONNECTIONS>::const_iterator c_i = connections_vector.begin();
c_i != connections_vector.end(); c_i++ ) {
temp.Format( "%s:%d:%d:%lu", ( LPCTSTR )c_i->their_ip,
c_i->their_port, c_i->our_sd, c_i->their_pa );
conn.push_back( temp );
cnt++;
}
}
return cnt;
}
void CConnectionsDoc::update_connections( const uint sd )
{
std::vector<ACTIVE_CONNECTIONS>::iterator iter = connections_vector.begin();
while( iter != connections_vector.end() ) {
if( iter->our_sd == sd ) {
connections_vector.erase(iter);
break;
}
iter++;
}
}
typedef struct active_connections
{
CString their_ip;
unsigned int their_port;
unsigned int our_sd;
unsigned long their_pa;
} ACTIVE_CONNECTIONS;
example data
their_ip "192.168.1.125"
their_port 60849
our_sd 1096
their_pa 2097260736
This is a Visual Studio 2012 C++ app and from a debugging session using a dump file I found the following values:
initialized=1
connections_vector size=8
connections_vector capacity=13
connections_vector entries 0-7 have valid data and debugger does not show any entries past element 7
cnt=13 at the time of the crash (odd it is the same size of the capacity)
conn size=13
conn capacity=13
std::vector conn has the 8 correct entries from the connections_vector plus 5 entries that look like valid data, but connections_vector.erase(it) was called in another function to remove disconnected entries prior to calling get_active_connections.
It appears that the const_iterator went beyond connections_vector.end() until it tried to access one element beyond the capacity of the connections_vector and crashed, but I don't see how that is possible. Any ideas? Thanks in advance.

You tried to erase some of the objects from the same vector. If you don't use erase remove idiom, data will not be cleaned up from vector. On top of that you did erase operation inside a loop, so iterator is invalidated. Please refer following more details
Iterator invalidation rules
http://en.wikipedia.org/wiki/Erase–remove_idiom

Related

Removing first three elements of 2d array C++

So here's my problem.. I have a 2d array of 2 char strings.
9D 5C 6S 9D KS 4S 9D
9S
If 3 found I need to delete the first 3 based on the first char.
card
My problem is I segfault almost anything i do...
pool is the 2d vector
selection = "9S";
while(col != GameBoard::pool.size() ){
while(GameBoard::pool[col][0].at(0) == selection.at(0) || cardsRem!=0){
if(GameBoard::pool[col].size() == 1){
GameBoard::pool.erase(GameBoard::pool.begin() + col);
cardsRem--;
}
else{
GameBoard::pool[col].pop_back();
cardsRem--;
}
}
if(GameBoard::pool[col][0].at(0) != selection.at(0)){
col++;
}
}
I've tried a series of for loops etc, and no luck! Any thoughts would save my sanity!
So I've tried to pull out a code segment to replicate it. But I can't...
If I run my whole program in a loop it will eventually throw a segfault. If I run that exact code in the same circumstance it doesn't... I'm trying to figure out what I'm missing. I'll get back in if I figure out exactly where my issue is..
So in the end the issue is not my code itself, i've got memory leaks or something somewhere that are adding up to eventually crash my program... That tends to be in the same method each time I guess.
The safer and most efficient way to erase some elements from a container is to apply the erase-remove idiom.
For instance, your snippet can be rewritten as the following (which is testable here):
using card_t = std::string;
std::vector<std::vector<card_t>> decks = {
{"9D", "5C", "6S", "9D", "KS", "4S", "9D"},
{"9S"}
};
card_t selection{"9S"};
// Predicate specifing which cards should be removed
auto has_same_rank = [rank = selection.at(0)] (card_t const& card) {
return card.at(0) == rank;
};
auto & deck = decks.at(0);
// 'std::remove_if' removes all the elements satisfying the predicate from the range
// by moving the elements that are not to be removed at the beginning of the range
// and returns a past-the-end iterator for the new end of the range.
// 'std::vector::erase' removes from the vector the elements from the iterator
// returned by 'std::remove_if' up to the end iterator. Note that it invalidates
// iterators and references at or after the point of the erase, including the
// end() iterator (it's the most common cause of errors in code like OP's).
deck.erase(std::remove_if(deck.begin(), deck.end(), has_same_rank),
deck.end());
So for anyone else in the future who comes across this...
The problem is I was deleting an element in the array in a loop, with the conditional stop was it's size. The size is set before hand, and while it was accounted for in the code it still left open the possibility for while(array.size() ) which would be locked in at 8 in the loop be treated as 6 in the code.
The solution was to save the location in the vector to delete and then delete them outside of the loop. I imagine there is a better, more technical answer to this, but it works as intended now!
for (double col = 0; col < size; ++col)
{
if(GameBoard::pool[col][0].at(0) == selection.at(0)){
while(GameBoard::pool[col][0].at(0) == selection.at(0) && cardsRem !=0){
if( GameBoard::pool[col].size() > 1 ){
GameBoard::pool[col].pop_back();
cardsRem--;
}
if(GameBoard::pool[col].size() <2){
toDel.insert ( toDel.begin() , col );
//GameBoard::pool.erase(GameBoard::pool.begin() + col);
cardsRem--;
size--;
}
}
}
}
for(int i = 0; i< toDel.size(); i++){
GameBoard::pool.erase(GameBoard::pool.begin() + toDel[i]);
}

Vector iterator + offset out of range error thrown incorrectly

I have written code for an evolving neural network and one of my classes has the following member function:
bool Brain::makeLayer(int pos)
{
int preSize = layers.size();
layers.insert(layers.begin() + pos, std::vector<Cell*>{});
return layers.size() > preSize;
}
where layers is defined as std::vector<std::vector<Cell*>> layers
I am getting an error vector + offset out of range on the line layers.insert(layers.begin() + pos, std::vector<Cell*>{});
Through some debugging, the size of layers is 1 and pos is also set as 1.
I have tried testing with different values of pos, and if called directly makeLayer(1) works as intended...
How it should work, layers.begin() + pos should be equal to layers.end() for a vector of size 1, and so when insert is called at that position, it should simply insert a std::vector<Cell*>{} at the end of layers, but it does not and throws the aforementioned error instead.
Edit: The containing class Brain guarantees that any call to makeLayer() will have a valid value pos such that layers.begin() + pos never exceeds layers.end(), the crux of my question is that insert() is throwing an error when that should not be possible. A std::vector of size 1 should never fail on layers.insert(layers.begin() + 1, val) unless the system runs out of memory and it my system is not running out of memory.
If you want to append a value to a std::vector, you should just use std::vector::push_back.
You are over engineering, since there is already a function for that purpose.
EDIT: I think the problem you're getting at is that when you add layers.begin() + pos, pos is probably bigger than layers.size(), that's why you aren't even able to check if layers.begin() + pos == layers.end(), you're incrementing an iterator out of bounds.
This seemed to fix the issue, but creates higher overhead (for obvious reasons).
bool Brain::makeLayer(int pos)
{
int preSize = layers.size();
layers = insert(layers, pos, std::vector<Cell*>{});
return layers.size() > preSize;
}
where insert() is defined as:
template<typename T>
std::vector<T> insert(std::vector<T>tgt,int pos, T item) {
std::vector<T> temp(tgt.size()+1);
int tgtIndex = 0;
if (pos > temp.size()) {
//this function is for debugging, first param is file name, then error message, then is the error fatal
errorOut("Lib", "Cannot add element to vector because pos is out of range", true);
}
for (int i = 0; i < temp.size(); i++) {
if (pos == i) {
temp[i] = item;
}
else {
temp[i] = tgt[tgtIndex];
tgtIndex++;
}
}
return temp;
}

Segfault on inserting into std::vector with insert member function of std::vector

When I insert into the vector like this :
resVec.insert(frontIter , vec[idx]);
I get a seg fault , but if I do
*frontIter = vec[idx];
It works without any problems. I know that the []operator has the capacity to allocate space for the object and then insert it, is the error that insert does not allocate space and it needs the space to be already allocated when insert is called at a position ?
I think this error is due to my confusion about what this does :
vi vec(10);
Is this similar to vec.resize(10) or vec.reserve(10)
Also does insert not work as say position 9 after I have called vec.reserve(10) ?
This is the code segment, just to make sure that I am not missing anything.
using vi = std::vector<int>;
using size = std::size_t;
// return vi after partition
vi partition_space(const vi & vec, size n)
{
vi resVec(vec.size());
int partVal = vec[n];
//resVec[n] = partVal;
// iterators to the back and front of the resVec.
// insertion will happen at the iters
vi::iterator frontIter = resVec.begin();
vi::reverse_iterator backIter = resVec.rbegin();
for(size idx = 0 ; idx < vec.size() ; ++idx)
{
if(idx == n)
{
continue;
}
if(vec[idx] < partVal) // insert in front of partVal
{
// *frontIter = vec[idx];
resVec.insert(frontIter , vec[idx]);
++frontIter;
}
else if(vec[idx] > partVal)// insert at back of n
{
*backIter = vec[idx];
++backIter;
}
else // repeated elements .. random choose to put it in front.. both choice does not matter
{
//resVec.insert(frontIter , vec[idx]);
*frontIter = vec[idx];
++frontIter;
}
}
frontIter++;
if(!std::distance(frontIter , backIter.base()))
{
std::cout << " ! " << std::endl;
}
*backIter = partVal;
return resVec ; // nrvo
}
Error is due to invalidation of iterator frontIter after first insert is happened. Here is whats going on:
Code allocate vector vec with 10 elements in it.
New element is inserted into position frontIter, this trigger vector storage re-allocation because vector out of it capacity so insert code reallocate inner storage to accommodate the insert. So this operation invalidate all vec iterators
Code try to insert new element by using old (invalidated) iterator... - seg-fault!

c++ boost map program crash after erase

I have a problem and dont know how to proper solve it or WHY the error appear.
To my problem:
I have 1 loop which execute a function every 2 seconds. That functions does a for() function and erase all entrys which remaining time is at 0. If remaining time is not 0 then it will decrease it by 2000 (2sec).
But after erasing an entry the program crashes...
boost map:
boost::unordered_map<unsigned int, sBUFF_INFO*> p_BuffInfo;
function which get executed from 2 seconds loop
void CSkill::DecreaseAllBuffRemTime()
{
for( itertype(p_BuffInfo) it = p_BuffInfo.begin(); it != p_BuffInfo.end(); it++ )
{
sBUFF_INFO* buff = it->second;
if(buff != NULL)
{
if(buff->dwTimeRemaining <= 0)
{
this->DelPcBuffInfo(buff->tblidx)
}else{
buff->dwTimeRemaining -= 2000;
}
}
}
}
DelPcBuffInfo function:
void CSkill::DelPcBuffInfo(unsigned int tblidx)
{
p_BuffInfo.erase(tblidx);
}
Now after DelPcBuffInfo gets executed the program crash.
At this line it crash:
sBUFF_INFO* buff = it->second;
At debug:
Unhandled exception at 0x00578e0f in GameServer.exe: 0xC0000005:
Access violation reading location 0xddddddd9.
it + node_ = hash_ CXX0030; Error: expression cannot be evaluated
I dont really understand why this error appear..
edit:
If I add a "return" after this->DelPcBuffInfo(buff->tblidx) then the program dont crash..
Adding or removing items from a container will often invalidate your iterators. Check the documentation for unordered_map iterators or here: Iterator invalidation in boost::unordered_map
the correct idiom is
for( itertype(p_BuffInfo) it = p_BuffInfo.begin(); it != p_BuffInfo.end(); )
{
sBUFF_INFO* buff = it->second;
if(buff != NULL)
{
if(buff->dwTimeRemaining <= 0)
{
it = this->DelPcBuffInfo(buff->tblidx)
}else{
buff->dwTimeRemaining -= 2000;
it++;
}
}
}
ie dont increment in the loop. Instead increment if you dont delete otherwise have the delete operation return the new iterator. Thats why remove returns an iterator pointing at the next element
This is courtesy of the awesome Scott Myers
To add to the existing answers pointing out the erase-iterator idiom: The reason for you crash is that the iterator it is invalidated due to the removal of the element. Thus, the increment on the (invalid) operator causes undefined behaviour and it will point to some arbitrary memory block. Dereferencing the "iterator" then crashes your program.
To avoid this problem, apply the idiom as demonstrated in the other answers, that is
* Use the iterator version of erase. It returns an iterator to the next element ( which may be end())
* Use the return value of this erase as new value of it. Since it already points to the next element, do not increment again (otherwise you may skip an element in your map or cause undefined behaviour if it already points to the end of the map.
* Only increment the iterator yourself, when you did not erase an element.
Note: If your intention is to get rid of the sBUFF_INFO element completely upon removal from the map, your programm shows a memory leak. Erasing the pointer from the map does not delete the pointed-to memory. You need to delete the pointee yourself (or use an appropriate smart pointer).
void CSkill::DecreaseAllBuffRemTime()
{
auto it = p_BuffInfo.begin();
while( it != p_BuffInfo.end() )
{
sBUFF_INFO* buff = it->second;
if(buff)
{
if(buff->dwTimeRemaining <= 0)
{
// probably delete buff too
it = p_BuffInfo.erase(it);
} else {
buff->dwTimeRemaining -= 2000;
++it;
}
} else {
++it;
}
}
}

Delete and add elements to vector inside main loop

I searched before but couldn't find any answers. I am somewhat new to c++, so hopefully this question won't be too stupid.
I am trying to add and remove elements in a vector, in my case populated with particles during a big update or drawing loop over all particles. For example remove some particles because they died, but also add a few other ones because one particle collided with an object and I want to show a small particle burst at the point of collision. I made this simple test code in a demo file to get to the bottom of the problem.
I think the problem is since I delete and add particles the iterator pointer becomes invalid. Deletion works, but when I add a few random ones I get a null pointer. the code below is somewhat verbose, I know I should use iterators with begin() and end() but I had the same problem with those, and played with the code a bit, trying more javascript array style looping because I am more familiar with that.
void testApp::drawParticles()
{
int i=0;
int max = particles.size();
vector<Particle*>::iterator it = particles.begin();
while ( i < max ) {
Particle * p = particles[i];
if ( ofRandom(1) > .9 ) {
it = particles.erase(it);
max = particles.size();
} else {
ofSetColor(255, 255, 0);
ofCircle( p->x, p->y, p->z, 10);
if ( ofRandom(1) < .1 ) addSomeNewOnes();
i++;
it++;
}
}
}
void testApp::addSomeNewOnes()
{
int max = ofRandom(4);
for ( int i=0; i<max; i++ ) {
Particle * p = new Particle();
p->x = ofRandom( -ofGetWidth()/2, ofGetWidth()/2 );
p->y = ofRandom( -ofGetHeight()/2, ofGetHeight()/2 );
p->z = ofRandom( -ofGetHeight()/2, ofGetHeight()/2 );
particles.push_back( p );
}
}
Every time you insert in to a vector, the iterators to it are potentially invalidated. You cannot do this:
if ( ofRandom(1) < .1 ) addSomeNewOnes();
it++
Because after the call to addSomeNewOnes(), it is invalid.
You can use the iterator returned by a call to vector::insert, but in your case that would mean re-engineering your code.
This is something you might want to do, anyway, as your code is a bit kludgy.
You could loop at it from the end, which should allow you to delete your current (since you're only deleting off of the end) and add new ones which get added to the end:
Vector<Particle*>::iterator it = particles.end();
while (iter != particles.begin()) {
Particle * p = *iter;
if ( ofRandom(1) > .9 ) {
particles.erase(iter);
} else {
ofSetColor(255, 255, 0);
ofCircle( p->x, p->y, p->z, 10);
if ( ofRandom(1) < .1 ) addSomeNewOnes();
}
iter--;
}
If you are not adding, based on the info here, iterators in STL are stable so you should be able to iterate forwards and still be able to achieve the same result.
Iterators are invalidated in some cases when the underlying data changes.
You'll have to break out of the loop and start again.
You should be able to do that by wrapping your whole drawParticles function in a while(notDone) loop, and setting notDone to true when you're done modifying the vector.
Here's another SO question with the rules: Iterator invalidation rules
it = particles.erase(it);
will return an iterator pointing to the new location of the element following the one erased. If the one erased happens to be the last one, it will point to particles.end(). it++ on "end" is an error.
Also, if:
if ( ofRandom(1) < .1 ) addSomeNewOnes();
evaluates to true and addSomeNewOnes() is called, as others have said, that will also invalidate the iterator.
Are you inserting and deleting at the location of the iterator? If so,
insert and erase return iterators which will be valid, and you can use
those. Something like:
std::vector<T>::iterator i = v.begin();
while ( i != v.end() ) {
if ( someCondition ) {
i = v.erase( i );
} else {
++ i;
}
}
is a more or less standard idiom.
For random insertions and deletions, you have to work with indexs, which
you update according to the number of elements inserted or deleted, and
whether the insertion or deletion was in front of or behind the current
position.
There's an easy way to make this work correctly without worrying about invalidation rules: just build a new vector for the next iteration.
typedef vector<Particle*> ParticleVector;
// modifies the particle vector passed in
void testApp::drawParticles(ParticleVector &particles)
{
ParticleVector next;
next.reserve(particles.size()); // seems like a reasonable guess
for (auto it = particles.begin(); it != particles.end(); ++it)
{
Particle *p = *it;
if (ofRandom(1) > .9) {
// don't copy to the next cycle
delete p;
} else {
// copy to the next cycle
next.push_back(p);
ofSetColor(255, 255, 0);
ofCircle(p->x, p->y, p->z, 10);
if (ofRandom(1) < .1)
addSomeNewOnesTo(next);
}
}
particles.swap(next);
}
Note how much easier it is to refactor like this when you're not using globals, btw.
void testApp::addSomeNewOnesTo(ParticleVector &particles)
{
int max = ofRandom(4);
for ( int i=0; i<max; i++ ) {
Particle * p = new Particle();
p->x = ofRandom( -ofGetWidth()/2, ofGetWidth()/2 );
p->y = ofRandom( -ofGetHeight()/2, ofGetHeight()/2 );
p->z = ofRandom( -ofGetHeight()/2, ofGetHeight()/2 );
particles.push_back( p );
}
}
On another note : Isn't there a memory leak in your implementation?
You are using
vector<Particle*> particles
and also using particles.erase().
Wont that just delete your pointer to Particle,and not created object?