Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QVector::append() what reason for explicit copying?

Tags:

c++

qt

template <typename T>
void QVector<T>::append(const T &t)
{
    const T copy(t);
    const bool isTooSmall = uint(d->size + 1) > d->alloc;
    if (!isDetached() || isTooSmall) {
        QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow :     QArrayData::Default);
        reallocData(d->size, isTooSmall ? d->size + 1 : d->alloc, opt);
    }
    if (QTypeInfo<T>::isComplex)
        new (d->end()) T(copy);
    else
        *d->end() = copy;
    ++d->size;
}

What is the reason to make const T copy(t) instead of passing t by value into the method? What is the difference between this and:

template <typename T>
void QVector<T>::append(const T t)
{
    const bool isTooSmall = uint(d->size + 1) > d->alloc;
    if (!isDetached() || isTooSmall) {
        QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow :     QArrayData::Default);
        reallocData(d->size, isTooSmall ? d->size + 1 : d->alloc, opt);
    }
    if (QTypeInfo<T>::isComplex)
        new (d->end()) T(t);
    else
        *d->end() = t;
    ++d->size;
}
like image 452
Grief Avatar asked Jun 11 '15 20:06

Grief


2 Answers

QVector requires elements to be assignable data types, which means they

must provide a default constructor, a copy constructor, and an assignment operator.

Their version of append enforce all, while your version will not enforce copy construction if QTypeInfo<T>::isComplex is false and optimized away.

Note: QTypeInfo<T>::isComplex is resolved at compile time.

I suspect it is a legacy requirement, as QVector already existed in Qt2, which date from 1999 well before c++ standardization.

like image 198
UmNyobe Avatar answered Sep 29 '22 19:09

UmNyobe


I can think of 2 possible reasons.

  1. It follows the style of the rest of the stl, copy and swap and pass by const &. Neither of those do any good performance or const correctness wise in this situation; but it does keep the style consistent.

  2. Because the parameter is bound to a reference, it avoids copy elision on the function call. And because the items in a vector must be assignable( ie not const ), it avoids copy elision on the assignment into the Vector

This makes the code MUCH more portable and consistent across compilers. Which is probably a big deal for the stl.

Copy Elision Wikipedia Entry

31) When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization.123 This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

— when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

like image 39
8bitwide Avatar answered Sep 29 '22 21:09

8bitwide