[Development] What's Q_PRIMITIVE_TYPE for?

Thiago Macieira thiago.macieira at intel.com
Fri Nov 13 07:48:21 CET 2020


On Thursday, 12 November 2020 07:07:53 PST Lars Knoll wrote:
> So except for the memset(0) for default construction, Primitive and Trivial
> have the same conditions in your list here. My proposal would be to drop
> the memset(0) optimisation and with that unify those two groups.

Not exactly. The distinctions come up at these points (see 2 and 3):

1) extending the container with new elements (resize() with sufficient 
capacity already allocated or constructor with element count): memsettable 
types can benefit from memset(0), as can most trivial types, except those 
containing pointer-to-member-object.

2) reallocating the container: relocatable types (which include all trivially-
copyable types) can be relocated by memcpy, which in turn means they can be 
relocated by realloc().

2b) relocating elements without reallocating (insertion): same as #2

3) detaching: trivially copyable types can be copied with memcpy(), but 
relocatable ones cannot

Q_PRIMITIVE_TYPE is currently something more restrictive than trivial type 
because of #1.

> (Note: I'm completely ignoring the lifetime issues at just blessing a block
> of memory and saying "there are N objects here". Thiago is right, we
> shouldn't ignore that. But I'm not sure how, except by biting the bullet
> and calling constructors/destructors, then relying on the compiler to do
> the right thing.)
> 
> Those lifetime issues need to be tackled differently. One option could be to
> abandon all our optimizations in a checked build, and only enable them in
> release mode.

We have to assume that any build with optimisations turned on means a checked 
build. Therefore, your proposal is self-contradictory.

I propose we ignore the lifetime issues *for* *now*. We need a proper language 
solution to declare objects' lifetime has started when we do either of the 
three operations above, without loss of performance afforded by the memcpy / 
memset. So either the language gives us a std::launder-like interface to bless 
the fait accompli or the compilers give us equivalent performance without such 
an interface. The relocation of non-trivially copyable types will likely have 
a language update because the current direction seems to include adding a 
destructive move operation.

But we will not be able to ignore the problem forever and I think the bill 
will come due before the end of the Qt 6 lifetime. For that reason, I am 
asking we decide which of the above is worth. I think:

1) not worth memsetting and very likely the compilers can be fixed to 
optimise. The benefit of memset compared to the whole operation (including 
malloc()) may not be worth the hassle

2) worth it because the language seems to be going in the direction we want 
and have showed the way for the last 15 years (relocatable types, destructive 
move)

3) uncertain; if the compilers do #1, it's likely they'll do #3 too.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel DPG Cloud Engineering





More information about the Development mailing list