[Development] What's Q_PRIMITIVE_TYPE for?
Thiago Macieira
thiago.macieira at intel.com
Wed Nov 11 18:14:07 CET 2020
On Monday, 9 November 2020 08:16:51 PST Giuseppe D'Angelo via Development
wrote:
> >> 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.
If we don't need the memset-as-initialisation, we can relax the "primitive
type" to an actual C++ category: trivially-copyable type. We're already
renaming the Q_MOVABLE_TYPE category to align with future standard direction
and calling it Q_RELOCATABLE_TYPE.
A trivially copyable class type has (http://eel.is/c++draft/class.prop#1):
* a non-deleted, trivial copy constructor or move constructor
* a non-deleted, trivial destructor
This differs from relocatability by requiring the trivial destructor, which
means we can forego calling it in QMetaType (in containers I'd expect the loop
simply expands to no code).
A trivially-copyable class need not have a trivial constructor (http://eel.is/
c++draft/class.default.ctor#3), but we can add that requirement too, which
would make our requirement even stronger, at trivial type. Note that a trivial
constructor does not imply the zero-initialised object is equivalent to the
default construction type. This example from Peppe's other email is a trivial
type and yet its default (constexpr) construction is not all zeroes:
struct C { int A::* ptr; };
see <https://gcc.godbolt.org/z/81dacG>.
In fact, I think pointer-to-member-object is the only example of a trivial
construction to non-zero-bits in either ABI that matters. For everything else,
a memset-to-zero construction will match the default (trivial, constexpr)
constructor. And for PMOs, it will create a valid if non-default
representation.
So my recommendation is:
1) deprecate Q_PRIMITIVE_TYPE and rename to Q_TRIVIAL_TYPE
2) *not* use memset-to-zero construction anywhere
#2 implies changing QPodArrayOps, which does use memset, to use a loop calling
the default constructor. Two of the four compilers do optimise that into a
call into memset: https://gcc.godbolt.org/z/Ks3M5h. And there's nothing the
ICC team likes to work on more than losing on a benchmark.
--
Thiago Macieira - thiago.macieira (AT) intel.com
Software Architect - Intel DPG Cloud Engineering
More information about the Development
mailing list