PDA

View Full Version : QValueVector in Qt 3(.3.8) is broken



fear
4th July 2007, 18:13
I have put a lot of effort to rewrite huge part of my app to work with QValueVector but all in vain. Below I present proof of this broken component. Correct me if I'm wrong and I'll be happy.

My code:


qDebug(">");
playlistsList::iterator i, j;
i = playlists.begin();
j = i;
i += where;

//qDebug(playlists.at(which).name);
//qDebug((*i).name);

for (int i = 0 ; i != playlists.count() ; i++, j++)
{
qDebug(playlists.at(i).name + " " + (*j).name);
}

qDebug("i'll insert " + playlists.at(which).name + " before " + (*i).name);

playlists.insert(i, playlists.at(which));

for (int i = 0 ; i != playlists.count() ; i++)
qDebug(playlists.at(i).name);

qDebug("after redundant removed");

i = playlists.begin();
j = i;
i += (which + 1);

playlists.erase(i);

for (int i = 0 ; i != playlists.count() ; i++, j++)
qDebug(playlists.at(i).name + " " + (*j).name);

qDebug("");
qDebug("");


Results after first execution of above code are correct:


>
aa aa
bb bb
i'll insert bb before aa
bb
aa
bb
after redundant removed
bb bb
aa aa


Second execution gives INCORRECT result:


>
bb bb
aa aa
i'll insert aa before bb
bb
bb
aa
after redundant removed
bb bb
bb bb


Can anyone help me?

jacek
4th July 2007, 19:41
Could you post a minimal compilable example?

fear
5th July 2007, 08:29
/**
Broken QValueVector demo (Qt 3.3.8, GCC 4.1.1)
@author amdfanatyk

compilation: c++ qvalvecshit.cpp -o valvec -lqt-mt
**/

#include <qstring.h>
#include <qvaluevector.h>

struct elem
{
elem() {}
elem(const QString & _s1, const QString & _s2) { s1 = _s1; s2 = _s2; }

QString s1;
QString s2;
};

typedef QValueVector<elem> elemsList;

void printList(const elemsList & list)
{
qDebug("---");

for (int i = 0 ; i != list.count() ; i++)
qDebug(list[i].s1 + " " + list[i].s2);

qDebug("---");
}

void insertElem(elemsList & e)
{
if (e.count() < 2)
return;

elemsList::iterator i = e.begin();

printList(e);

QString e1s1 = e.at(1).s1;
QString e0s1 = (*i).s1;

qDebug("*- i'll insert " + e1s1 + " before " + e0s1);

e.insert(i, e.at(1));

printList(e);

if ((e.at(0).s1 != e1s1) || (e.at(1).s1 != e0s1))
qDebug("Ooops!");
else
qDebug("OK");
}

int main()
{
elemsList elems;

elem e1("a", "aa");
elem e2("b", "bb");

elems.append(e1);
elems.append(e2);

insertElem(elems);
insertElem(elems);

return 0;
}




---
a aa
b bb
---
*- i'll insert b before a
---
b bb
a aa
b bb
---
OK
---
b bb
a aa
b bb
---
*- i'll insert a before b
---
b bb
b bb
a aa
b bb
---
Ooops!

jacek
5th July 2007, 13:32
I've changed
e.insert(i, e.at(1));
to
elem el = e.at(1);
e.insert(i, el);
and it seems to work OK now.

IMO the problem is that at() returns a reference, which is valid only while the vector remains unchanged. But insert() has to make space for the new item, so it moves existing items and the reference becomes invalid.

fear
5th July 2007, 14:45
Thanks. Now it works but I don't think I'll use QValueVector and QTL. For me that's a bug. insert() should insert a copy of, so first it should make a copy and then insert it. To get it work I must make one copy and then vector makes another copy and I waste a lot of memory, it sucks. When I use my own engine I only change values of pointers - there is no need to make copies and remove redundant objects. With QPtrVector I think I'll have similar problems.

jacek
5th July 2007, 15:58
For me that's a bug. insert() should insert a copy of, so first it should make a copy and then insert it.
insert() itself is OK. The problem is that the item is passed by reference.


When I use my own engine I only change values of pointers - there is no need to make copies and remove redundant objects.
That's how QPtrVector works. QValueVector, just like std::vector, stores items, not pointers, so it has to copy them. But if you have your own collection that suits you better, just use it.