PDA

View Full Version : Weird behavior in QList.erase



Ozonkor
1st May 2015, 14:09
Hello All!
I've created my first GUI Application, using QT C++ in Windows. Unfortunately, it throws runtime error. Can anyone help me with this code:


void Manager::vectorsDifference(QVector<Data*> *vectorFirst, QVector<Data*> *vectorSecond, QVector<Data*> *vectorOutput)
{
QVector<Data*>::iterator itFirst;
QVector<Data*>::iterator itSet;
QVector<Data*>::iterator itDel;
QVector<Data*> vDeleted;
int iVec;

for(itFirst = vectorFirst->begin(); itFirst != vectorFirst->end(); itFirst++)
{
vectorOutput->push_back(*itFirst);
}
for(itSet = vectorOutput->begin(); itSet != vectorOutput->end(); itSet++)
{
for(iVec = 0; iVec != vectorSecond->size() - 1; iVec++)
{
if ((*itSet)->x == vectorSecond->at(iVec)->x &&
(*itSet)->y == vectorSecond->at(iVec)->y )
{
vDeleted.push_back(*itSet);
vectorOutput->erase(itSet);
}
}

for(itDel = vDeleted.begin(); itDel != vDeleted.end(); itDel++)
{
if( (*itSet)->x == (*itDel)->x &&
(*itSet)->y == (*itDel)->y)
{
vectorOutput->erase(itSet);
}
}
}
}

class Data
{
public:
qString x,y;
}

pseudocode:
QVector First { {a,a}, {a,b}, {b,a} }
QVector Second { {a,a}, {a,c}, {a,b}, {a,a} }
What I want:
QVector output { {b,a} }


Description:
Vectors(First and Second) stores data of class Data, which contains x and y info. In one vector, there might be a few similar files with the same x and y. I want to create vector of elements, which are only in one vector, but not in the other. That's why I've created another vector (vDeleted) to store data that was deleted, but it might occur again.
The runtime exception is thrown, while data is being erased.

jefftee
1st May 2015, 15:24
The STL style iterators for Qt containers may become invalidated when you change the contents of the container. If you want iterator stability when doing deletes on container items, look at the Java style iterators.

anda_skoa
2nd May 2015, 09:11
erase() returns the iterator pointing to the next element.



for (it = container.begin(); it != container.end(); /* no ++ here */) {
if (condition) {
it = container.erase(it);
}else {
// only increment if no delete happened
++it;
}
}

jefftee
3rd May 2015, 00:14
Does the following accomplish what you want?



vectorOutput = vectorFirst;

QVectorIterator<Data*> itOutput(vectorOutput);
QVectorIterator<Data*> itSecond(vectorSecond);

while (itOutput.hasNext())
{
Data *d1 = itOutput.next();
vectorSecond.toFront();
while (itSecond.hasNext())
{
Data *d2 = itSecond.next();
if (d1->x == d2->x && d1->y == d2->y)
{
vectorDeleted.push_back(d1);
vectorOutput.removeOne(d1);
}
}
}

d_stranz
3rd May 2015, 22:07
erase() returns the iterator pointing to the next element.

But the trick to this is you have to continuously evaluate container.end() as part of the for() loop termination condition. You can't assign it to a variable prior to entering the for() loop, because the value it holds will become invalid as soon as the container content changes (either through insertion or erasure). In other words, this will not work:



QVector<Data *>::iterator it;
QVector<Data *>::iterator eIt = container.end();
for (it = container.begin(); it != eIt; /* no ++ here */) {
if (condition) {
it = container.erase(it);
}else {
// only increment if no delete happened
++it;
}
}