1+1=10

扬长避短 vs 取长补短

"Qt Macro: Q_DECLARE_TYPEINFO"

Definition

Q_DECLARE_TYPEINFO is used to specialise a template class called QTypeInfo.

#define Q_DECLARE_TYPEINFO_BODY(TYPE, FLAGS) \
class QTypeInfo<TYPE > \
{ \
public: \
    enum { \
        isComplex = (((FLAGS) & Q_PRIMITIVE_TYPE) == 0), \
        isStatic = (((FLAGS) & (Q_MOVABLE_TYPE | Q_PRIMITIVE_TYPE)) == 0), \
        isLarge = (sizeof(TYPE)>sizeof(void*)), \
        isPointer = false, \
        isDummy = (((FLAGS) & Q_DUMMY_TYPE) != 0), \
        sizeOf = sizeof(TYPE) \
    }; \
    static inline const char *name() { return #TYPE; } \
}

#define Q_DECLARE_TYPEINFO(TYPE, FLAGS) \
template<> \
Q_DECLARE_TYPEINFO_BODY(TYPE, FLAGS)

Where Q_DECLARE_TYPEINFO is used?

The documention says that:

Q_DECLARE_TYPEINFO( Type, Flags)

You can use this macro to specify information about a custom type Type. With accurate type information, Qt's generic containers can choose appropriate storage methods and algorithms.

Let's find where QTypeInfo is used in Qt's source code:

template <typename T>
class QList
{
    struct Node { void *v;
        Q_INLINE_TEMPLATE T &t()
        { return *reinterpret_cast<T*>(QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic
                                       ? v : this); }
    };
//...
template <typename T>
void QVector<T>::reallocData(const int asize, const int aalloc, QArrayData::AllocationOptions options)
{
//...
                if (QTypeInfo<T>::isStatic || (isShared && QTypeInfo<T>::isComplex)) {
                    // we can not move the data, we need to copy construct it
                    while (srcBegin != srcEnd) {
                        new (dst++) T(*srcBegin++);
                    }
                } else {
                    ::memcpy(static_cast<void *>(dst), static_cast<void *>(srcBegin), (srcEnd - srcBegin) * sizeof(T));
//...

TYPEINFO flags

We can find following code in qtypeinfo.h:

enum { /* TYPEINFO flags */
    Q_COMPLEX_TYPE = 0,
    Q_PRIMITIVE_TYPE = 0x1,
    Q_STATIC_TYPE = 0,
    Q_MOVABLE_TYPE = 0x2,
    Q_DUMMY_TYPE = 0x4
};
  • Q_PRIMITIVE_TYPE specifies that Type is a POD (plain old data) type with no constructor or destructor, or else a type where every bit pattern is a valid object and memcpy() creates a valid independent copy of the object.
  • Q_MOVABLE_TYPE specifies that Type has a constructor and/or a destructor but can be moved in memory using memcpy().
  • Q_COMPLEX_TYPE (the default) specifies that Type has constructors and/or a destructor and that it may not be moved in memory.

For QVector, When an insertion takes place, the elements that come after the point of insertion must be moved one position further. If T is a movable type, this is achieved using memmove(); otherwise, QVector needs to move the items one by one using operator=(). The same applies to removals in the middle.

{% img center /images/blog/2013/q_declare_typeinfo_qvector_insert.png %}

Reference

  • http://doc.qt.digia.com/qq/qq19-containers.html
  • http://www.drdobbs.com/c-made-easier-plain-old-data/184401508