[Development] What's Q_PRIMITIVE_TYPE for?

Giuseppe D'Angelo giuseppe.dangelo at kdab.com
Mon Nov 9 17:16:51 CET 2020


On 09/11/2020 11:33, Lars Knoll wrote:
>>> 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.
>> With this definition in mind, why is QUuid primitive, QVector3D primitive, but QSize not primitive? They all are non-trivial types, they all have default constructors that set their contents to 0. Which one is correct? Can the others be changed while keeping BC?
> If a type is relocatable, it’s default constructor memsets all bits of the object to 0, the copy constructor just does a memcpy of those bits and the destructor does nothing you can just as well mark the type as primitive.
> I think the fact that QSize is not marked primitive is a bug and should be fixed. Fortunately, changing that does not affect ABI.
>> Then: is this definition actually exploited anywhere?
> It’s being used to select the QPodArrayOps for QList. The advantage it that we in this case use memset() instead of constructors, and memcpy/memmove to copy or move data.
> This does still make a difference compared to Q_RELOCATABLE_TYPE, where we need to use a combination of memmove and copy constructors, and also need to take care of at least basic exception safety when constructing items in the list. For primitive types we can avoid both copy constructors and the rollback handling for potential exceptions.

Thank you! This is what I missed. And indeed this is what is missing 
from the Q_PRIMITIVE_TYPE documentation: the condition "every bit 
pattern is a valid object" is necessary but not sufficient. It also 
needs: "value construction sets all (non-padding) bytes to 0", which is 
what gets actually exploited in the current code.

This explains why QSize isn't primitive: every bit pattern is a valid 
QSize, but its default constructor sets the extents to -1. So you can't 
build a QSize by allocating memory and memsetting it to 0.

And I don't think that compilers are smart enough already to turn a for 
loop that is filling with zeros into a memset, so we need the type info 
for this. Or am I wrong?

>> The only other place that cares about primitive types is QMetaType, which uses this information to set the "NeedsConstruction" or "NeedsDestruction" type flags. But these type flags are never used anywhere inside of Qt; QMetaType value/copy/move constructs, and destructs, every type.
> This would actually be something to look into. We could avoid creating those methods, and instead have a flag and in those cases the implementation in QMetaType could simply use memset and memcpy.

To be honest, I don't see an advantage here, given QMetaType doesn't 
need to "bulk" construct or destroy N objects but only 1, and it could 
just call its constructor/destructor rather than short circuiting the 
operations to memset/memcpy.

Thank you,
Giuseppe D'Angelo | giuseppe.dangelo at kdab.com | Senior Software Engineer
KDAB (France) S.A.S., a KDAB Group company
Tel. France +33 (0)4 90 84 08 53, http://www.kdab.com
KDAB - The Qt, C++ and OpenGL Experts

-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 4329 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://lists.qt-project.org/pipermail/development/attachments/20201109/f8f9feac/attachment.bin>

More information about the Development mailing list