PDA

View Full Version : Question about qvector.h code of Qt 4



karapas
28th August 2007, 20:02
Hi all!
While I was looking at the code of qvector.h (the header file of QVector class - I use Qt 4.2.2) and I noticed something which I don't understand. For example, here is the implementation of the QVector:append() method:


template <typename T>
void QVector<T>::append(const T &t)
{
const T copy(t);
if (d->ref != 1 || d->size + 1 > d->alloc)
realloc(d->size, QVectorData::grow(sizeof(Data), d->size + 1, sizeof(T),
QTypeInfo<T>::isStatic));
if (QTypeInfo<T>::isComplex)
new (d->array + d->size) T(copy);
else
d->array[d->size] = copy;
++d->size;
}

So my question is:
What's the use of the copy variable? Is it there for a reason or is it redundant?

Would the following code:


template <typename T>
void QVector<T>::append(const T &t)
{
// const T copy(t);
if (d->ref != 1 || d->size + 1 > d->alloc)
realloc(d->size, QVectorData::grow(sizeof(Data), d->size + 1, sizeof(T),
QTypeInfo<T>::isStatic));
if (QTypeInfo<T>::isComplex)
new (d->array + d->size) T(t);
else
d->array[d->size] = t;
++d->size;
}

do the same thing as the original code?

The same practice seems to be used in other functions of QVector as well like in QVector::fill():


template <typename T>
QVector<T> &QVector<T>::fill(const T &from, int asize)
{
const T copy(from); //is it really needed???
resize(asize < 0 ? d->size : asize);
if (d->size) {
T *i = d->array + d->size;
T *b = d->array;
while (i != b)
*--i = copy;
}
return *this;
}

and probably in other classes too.

So, is this practice of creating a const copy (as an automatic variable) redundant or am I missing something???:)

jacek
28th August 2007, 20:26
Consider such code:
QVector<int> v;
...
v.append( v[0] );
What will happen if realloc() moves the data?

Michiel
28th August 2007, 21:19
So why pass t by reference in the first place then?

jacek
29th August 2007, 00:49
So why pass t by reference in the first place then?
Who knows? Maybe this problem was noticed after the interface was set or maybe to leave a possibility for more efficient implementation in future or for some other reason. You will have to ask the Trolls.

Anyway now it's just like if parameters were passed by value.

karapas
29th August 2007, 09:24
Thanks for the replies guys! jacek you are right! I did not notice that such a thing could happen in the first place! I 've just noticed that the same code exists in STL <vector> as well and there is an enlightening comment:


_Ty _Tmp = _Val; // in case _Val is in sequence

Thanks again!

Michiel
29th August 2007, 10:07
Hm. Perhaps it is to ensure that the type has a public copy constructor? I'm not sure if a pass-by-value parameter would ensure the same thing.

karapas
29th August 2007, 12:27
Hm. Perhaps it is to ensure that the type has a public copy constructor? I'm not sure if a pass-by-value parameter would ensure the same thing.

I think that pass-by-value parameter does exactly the same thing i.e it calls the copy constructor to create a copy of the passed object.


I think that an optimazation would be to create the copy only when resize (i.e call realloc) is needed. This would possibly result in a bit larger code but it would probably be better not to needlessly invoke the copy constructor in case that large objects are stored inside the QVector (for example images)