C++ Break out of a vector loop - c++

I have a method in a class LinkRepository, I am checking for duplicate entries in the vector array Datalinks, which is a member of the class. I loop through all the elements in the array to check in the new entry Datalink* datalink already exist in the array. If so then don't add, just exit the loop.
void LinkRepository::SaveLink(Datalink* datalink) {
bool Exist = false;
for(vector<Datalink*>::iterator dl = Datalinks.begin(); dl != Datalinks.end(); ++dl)
{
if((strstr((*dl)->ParentID, datalink->ParentID) != NULL) && (strstr((*dl)->ChildID,datalink->ChildID) != NULL))
{
Exist = true;
dl = Datalinks.end();
}
}
if(!Exist)
{
Datalinks.push_back(datalink);
}
};
My program seems to crash on the next loop of the statement dl = Datalinks.end();
I have no idea why it is crashing?

Replace
dl = Datalinks.end();
With:
break;
To exit the loop
Here is a simple example to illustrate why your solution can't work:
int i = 0;
for (; i != 10; ++i)
{
i = 10;
}
This loop will never end because i will be incremented to 11 before comparison i != 10

It is crashing because first you set the iterator to Datalinks.end() and then, upon leaving this iteration, the for loop itself increments the iterator, making an invalid operation.

for(vector<Datalink*>::iterator dl = Datalinks.begin(); dl != Datalinks.end() && !Exist; ++dl)
{
if((strstr((*dl)->ParentID, datalink->ParentID) != NULL) && (strstr((*dl)->ChildID,datalink->ChildID) != NULL))
{
Exist = true;
}
}
Like everyone had said you are iterating one over. So, it's going into unwanted memory locations resulting in a seg fault eventually. You have to realize that the ++dl is happening at the end of the loop.
Also, using a break statement here is ridiculous. You already have a bool, make use of it.

Related

C++ vector iterator not incremental

I've been having a headache with this problem. I've challenged myself to make a CLI space shooter, where you have you spaceship, lasers and meteors to shoot. The problem is this: whenever a laser or a meteor reaches the boundaries of our arena, I want to erase from the vector so that it wouldn't cluster it up. Here's how my working code looks now:
std::vector<Meteoras>::iterator itMet = meteorai.begin();
std::vector<Lazeris>::iterator itLaz = lazeriai.begin();
while (itMet != meteorai.end() || itLaz != lazeriai.end())
{
if (itLaz != lazeriai.end())
{
if (itLaz->getCoord()->x == j && itLaz->getCoord()->y == i)
{
itLaz->move();
++j;
if (itLaz->getCoord()->x >= ILGIS - 1) continue;
else std::cout << itLaz->getIcon();
}
++itLaz;
}
if (itMet != meteorai.end())
{
if (itMet->getCoord()->x - 1 == j && itMet->getCoord()->y == i)
{
itMet->move();
++j;
if (itMet->getCoord()->x <= 0) continue;
else std::cout << itMet->getIcon();
}
++itMet;
}
}
So there are two "continues" in there. Instead of them I tried placing iterator removals (as in itLaz = lazeriai.erase(itLaz) but that the program seemed to crash during runtime giving the error that I stated before. I tried doing other logical checks but that didn't seem to work either. I would appreciate if someone could explain a proper way of removing a useless object (in this case a meteor/laser) from a vector.
The comment about erase() invalidating an iterator is true. The part about needing to restart at the beginning is wrong. (You could do, but you certainly don't need to.)
erase() returns a still-valid iterator which points to the element after the erased item.
if( test for erasing )
{
itLaz = lazeriai.erase(itLaz);
}
else
{
++itlaz;
}
You might be able to refactor your code to use std::remove_if() instead.

Trouble removing elements from C++ vector

I'm trying to remove 'dead' bullets from my vector of bullets. Every frame, I'm calling the Bullet::update() function which looks like this:
void Bullet::update()
{
for(int i = 0; i != mAmmo.size(); i++)
{
if(mAmmo[i].sprite.getPosition().x > 700)
mAmmo[i].mAlive = false;
if(mAmmo[i].mAlive == false)
{
// I get a Debug Assertion Failed at runtime from this piece of code
mAmmo.erase(mAmmo.begin()+i);
}
if(mAmmo[i].mAlive == true)
{
mAmmo[i].sprite.move(mMovement);
}
}
}
Am I doing this completely incorrectly? This is the first time I've really used vectors more than just following through a tutorial. If I need to post any more code, just tell me. I've been working on this for the past few hours, so I'm a wee bit desperate to get this to work.
Thanks in advance!
You're easily walking into undefined behavior as soon as the ith element is the last element in your list. Use iterators, and pay special attention to the return value of erase(), as it automatically advances the iterator for you so your loop doesn't have to.
void Bullet::update()
{
for (auto it = mAmmo.begin(); it != mAmmo.end();)
{
if(it->sprite.getPosition().x > 700)
it->mAlive = false;
if (!it->mAlive)
{
// erase and get next iterator
it = mAmmo.erase(it);
}
else
{ // move and increment
it->sprite.move(mMovement);
++it;
}
}
}

Valgrind detects invalid read error in simple Iterator class

Valgrind detects an invalid read error I don't know how to fix or to be more precise: I don't know what the problem is.
Invalid read of size 8
at 0x443212: std::vector<Tile*, std::allocator<Tile*> >::end() const
by 0x44296C: Collection<Tile*>::Iterator::operator++()
The Iterator class is very simple (and actually a somewhat bad piece of programming) but sufficient for my needs right now. I think there are three methods you should know to hopefully help find my problem:
Iterator(size_t x, size_t y, const TileCollection& tiles)
: mTiles(&tiles)
, mX(mTiles->begin())
, mY(mTiles->at(x).begin())
{
std::advance(mX, x);
std::advance(mY, y);
bool foundFirst = false;
while (!foundFirst)
{
while (mY != mX->end() && *mY == 0) ++mY;
if (mY != mX->end()) foundFirst = true;
else
{
++mX;
if (mX != mTiles->end()) mY = mX->begin();
}
}
}
Iterator Iterator::operator++()
{
bool foundNext = false;
++mY;
while (!foundNext)
{
while (mY != mX->end() && *mY == 0) ++mY;
if (mY != mX->end()) foundNext = true;
else
{
++mX;
if (mX != mTiles->end()) mY = mX->begin();
}
}
return *this;
}
void TileCollection::add(Tile* tile)
{
Point2D p(tile->getPosition());
std::vector<Tile*> tmp(1, (Tile*)0);
if ((size_t)p.x >= mTiles.size())
mTiles.resize(p.x + 1, tmp);
if ((size_t)p.y >= mTiles.at(p.x).size())
mTiles.at(p.x).resize(p.y + 1, (Tile*)0);
mTiles.at(p.x).at(p.y) = tile;
++mNumTiles;
}
The actual code that is causing the valgrind error is the line:
while (mY != mX->end() && *mY == 0) ++mY;
...of the Iterator::operator++ method.
It looks to me that, at the least, the following line in operator++
if (mX != mTiles->end()) mY = mX->begin();
is lacking a suitable else-clause.
Consider what happens when mX actually reaches mTiles->end(): You will enter a new iteration of the outer while loop; the first line in that loop (the line that causes the Valgrind error) will evaluate mX->end() and thus attempt to dereference mX -- but mX is mTiles->end(), and it's not correct to dereference the end iterator of a collection since it doesn't actually reference an element of the collection. It looks to me as if this may be the cause of your Valgrind error.
(Note that the constructor contains essentially the same code.)
More generally, I think you need to think about how you handle reaching the end of your two-dimensional array. How does the client of your Iterator check whether it has reached the end of the iteration? How do you expect your operator++ to handle the case when it reaches the end of the two-dimensional array? Should it protect itself against getting called too often?
You can try to split up the statement in order get find out where the error occurs:
while (mY != mX->end()) // maybe here
{
if (*mY != 0) // maybe here
{
break;
}
++mY; // maybe here
}
Compiling with GCC compiler option -fno-inline helps to get a nicer stack-trace, which can help you to trace the error. It will also make your program very slow, so don't forget to remove it later.

Erasing vector element crashing the program

Why the follwoing code is failing ?
typedef vector<SOCKET /*socket*/> UIConnection;
UIConnection::iterator itrUICon;
for ( itrUICon = m_ListUIConnection.begin();itrUICon != m_ListUIConnection.end();itrUICon++)
{
if (*itrUICon == nSock)
{
itrUICon = m_ListUIConnection.erase(itrUICon);
}
}
You must remove the ++itrUICon in the for instruction.
UIConnection::iterator itrUICon;
for ( itrUICon = m_ListUIConnection.begin();itrUICon != m_ListUIConnection.end(); )
{
if (*itrUICon == nSock)
{
itrUICon = m_ListUIConnection.erase(itrUICon);
}
else ++itrUICon;
}
Probably because you are erasing the last item in the vector and then incrementing itrUICon in the increment part of the for statement when it is already equal to .end().
Prefer using the erase()/std::remove() idiom or at least move the increment out of the for statement and only perform it if you didn't preform an erase.

If condition , doesn't code execute code properly

This code takes a string from a dialog box , and compares it to data in a list,and if succesfull sets the selection on the element from list .
The problem i am having is with the if , it works if i only search the first element , if i try to search any other , it just ignore the if condition and goes till the end o the list .
void CMFC1Dlg::OnBnClickedButton6()
{
CString variable;
cautare.GetWindowTextA(variable);
variable = variable.MakeLower();
if(variable!="")
{
list<Contact*>::iterator seek;
bool flag = TRUE;
int i = 0 ;
while(flag)
{
seek = agenda.first_element();
if( ((CString)((*seek)->getLastName().c_str())).MakeLower() == variable ||
((CString)((*seek)->getFirstName().c_str())).MakeLower() == variable ||
((CString)((*seek)->getFirstAndLastName().c_str())).MakeLower() == variable ||
((CString)((*seek)->getLastAndFirstName().c_str())).MakeLower() == variable)
{
contactsVariable.SetCurSel(i);
this->OnLbnSelchangeList1();
flag=FALSE;
}
advance(seek,i);
i++;
if (i == agenda.list_size())
{
flag = FALSE;
}
}
}
else
MessageBox("No text on input ", "Error", MB_ICONERROR | MB_OK);
cautare.SetFocus();
cautare.SetWindowTextA("");
}
You are setting seek = agenda.first_element(); at the beginning of every iteration of the while loop. Move that statement outside the loop and it should work.
EDIT: You would also need to change the seek call to only seek 1, rather than i, since you're no longer throwing out the result of the previous seeks.
You should move seek = agenda.first_element(); out of the while loop.
Since you are iterating over a list of elements, why not use the begin() and end() method of the associated list. So you can iterate over each element and don't need to advance the iterator in each loop.
The code could look like this
list<Contract*>::iterator seek = agenda.begin();
while (flag && (seek != agenda.end())) {
// do the comparison
seek++;
}
You are only ever comparing the first element move advance(seek,i); like this:
while(flag)
{
seek = agenda.first_element();
advance(seek,i);
...