[Development] Container refactor update
André Pönitz
andre.poenitz at mathematik.tu-chemnitz.de
Thu Jun 21 01:59:41 CEST 2012
On Thu, Jun 21, 2012 at 01:06:16AM +0200, Marc Mutz wrote:
> On Thursday June 21 2012, André Pönitz wrote:
> > On Wed, Jun 20, 2012 at 08:52:55AM +0200, Marc Mutz wrote:
> > > Hi Thiago,
> > >
> > > [you knew this would be coming, I don't let you down]
> > >
> > > On Monday June 18 2012, Thiago Macieira wrote:
> > > > * port QList
> > >
> > > Before actually porting QList (esp. as I take the above to mean
> > > that QList won't be bound to void* slots anymore): Is there
> > > than *anything* in QList that QVector doesn't do at least as
> > > good or that could be ported over to QVector (reserving space
> > > in front for prepends comes to mind, though I'd argue that code
> > > that uses this a lot is broken by design anyway).
> >
> > Inserting in the middle of a container of complex data. In both
> > cases O(n), but a simple move of a block of pointers in one case
> > but not on the other.
>
> So that's a corner case of a corner case QList is optimized for. C++98 throw
> specifications would still be alive and kicking if that was a valuable
> goal :)
QList::append is not a corner case in my world.
> > Same for an append() that triggers
> > re-allocation actually.
> >
> > Contrary to popular believe the constant hidden in big-O _does_
> > matter in practice...
>
> Sorry, I was assuming familiarity with
> http://marcmutz.wordpress.com/effective-qt/containers/#the-data
> which suggests that QList doesn't outperform QVector even in its own sweet
> spot (QString, QByteArray).
I am afraid your randomly selected use case does not match my
randomly selected use case.
At least the results differ.
For, say,
#include <QList>
#include <QVector>
#include <math.h>
struct A
{
A() : a(sin(12)) {}
A(const A &b) : a(sin(b.a) + cos(b.a)) {}
int a;
};
struct Foo
{
A a[100];
};
int list()
{
QList<Foo> f;
for (int i = 0; i != 10000; ++i)
f.append(Foo());
return f.size();
}
int vector()
{
QVector<Foo> f;
for (int i = 0; i != 10000; ++i)
f.append(Foo());
return f.size();
}
int main()
{
return list() + vector();
}
callgrind just came up with a 3:1 advantage _in favour_ of QList.
And that ratio can be made look arbitrarily worse by adding more load
to the copy constructor.
> Then it should be called QArrayList and the QList name freed for an
> implementation with less surprising memory layout (ie. QVector).
>
> Anyway, the rally point for my post was Thiago's observation that
> QList<QString> with the new QString of 3*sizeof(void*) - I quote - "will be
> horrible". If you change QList to be efficient for QString again, what else
> do you have but a QVector?
>
> > > I haven't seen a single Qt developer team (Qt devs not
> > > excepting) that is fully aware of the performance
> > > characteristics and memory layout of QList.
> >
> > That's an interesting observation that does not _fully_
> > seem to match mine ;-}
>
> Case in point: QList<QModelIndex>, QList<QVariant> and QList<bool>. The first
> two copy-construct all elements onto the heap, the latter wastes 87.5% (on
> 64bit) of the allocated memory on padding.
>
> What's the rationale for preferring QList here? Wouldn't you agree that these
> would have better used QVector? Wouldn't you agree that changing QList to
> QVector all over Qt 5 is a bit too source-incompatible and that therefore
> backing QList by QVector would be a decent thing to do?
Replacing QList by QVector internally in cases where is makes sense is a no-brainer.
Making them equivalent, less so...
Andre'
More information about the Development
mailing list