vectors vs. lists
Marc Mutz
marc.mutz at uni-bielefeld.de
Thu Feb 19 09:46:35 GMT 2004
Hi!
Here's a nice Janitor's job:
I've recently stumbled across patches to KMail that use QValueList<int>
and don't do much more than appending, iterating or even indexing into
it. I'm sure there's more of this all over KDE since nearly everyone I
talked to in the last weeks about this was surprised. TT did a _very_
bad thing: Their API is full of *List, but sports very nearly no
*Vector's.
Now, all of you with an algorithm and datastructures training just sit
back and think about this a few seconds.
QValueList<> is a doubly linked list. Basically, you have a memory
overhead of 2*sizeof(void*) for the linking and, a malloc() for each
insertion, which is not only slow, but also has a noticable memory
overhead, esp. for such small sizes. Calculating the exact size of a
QValueList<int> with - say - 1000 entries is left as an excercise to
the reader.
Consider QValueVector. It lays out it's object in a continuous chunk of
memory. 1 malloc(), no overhead. So what's the drawback? The drawback
is that inserting elements in the middle or the front involves invoking
the copy ctor for each element following the insertion point. Plus the
reallocation if the reserved capacity is exceeded. But in most cases,
this is not relevant, such as with the append-and-iterate scenario, or
with trival copy ctors (such as int has), or even if you only have a
small number of items, say a few dozen, anyway. If you know the
approximate size of the result beforehand, you can avoid frequent
reallocations by using reserve(). Don't use QValueVector<T>( size_type,
const T& ), though, as that will call the copy ctor for each element.
Use reserve() and push_back()[1].
It's really funny how STL-trained people default to std::vector<> in all
their code, and you see std::list<> only very rarely, but you see
QValueList used as a default in KDE/Qt, and in ways that involve
indexing (O(n)! vs. O(1) in QVV). This loop, btw,:
for ( int i = 0 ; i < list.count() ; ++i )
doSomethingWith( list[i] );
is O(n^2). Whereas these:
for ( List::const_iterator it = list.begin() ; it != list.end() ; ++it )
doSomethingWith( *it );
for ( int i = 0 ; i < vector.size() ; ++i )
doSomethingWith( vector[i] );
are O(n).
Bottomline: If you can choose the container class to use, prefer
QValueVector over QValueList. And QValueVector<T*> over QPtrList<T>, if
you don't need the autodelete feature of QPtrList<> (the most visible
difference is that QPtrList<T> needs the type of the template argument
to be complete, while QValueFoo<T*> does not (fwd decl suffices), and
QPtrList won't be anymore in Qt4).
Basically, only use the list types if you know that vectors are
unsuitable (due to frequent insertions in the middle, altough those can
often be removed by copying into another container (think sorting)).
Tha janitorial job would involve finding wrong uses of QValueList and
fixing them to use QValueVector.
Marc
[1] I personally use STL-copmatible methods and iteration where
available, since those are standardised and won't go away with the next
Qt version.
--
There's a lot of "throwing the baby out with the bathwater" going on,
but the bathwater is so foul that many companies don't mind the
occasional loss of baby. -- Bruce Schneier on spam filters,
Crypto-Gram 07/2003
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
URL: <http://mail.kde.org/pipermail/kde-core-devel/attachments/20040219/9d66d815/attachment.sig>
More information about the kde-core-devel
mailing list