[Development] What's Q_PRIMITIVE_TYPE for?

Lars Knoll lars.knoll at qt.io
Thu Nov 12 16:07:53 CET 2020

On 12 Nov 2020, at 15:37, Giuseppe D'Angelo <giuseppe.dangelo at kdab.com<mailto:giuseppe.dangelo at kdab.com>> wrote:

Il 12/11/20 15:13, Lars Knoll ha scritto:
Is_trivial() explicitly states that you can memcpy/memmove objects and I really want to keep this. With your change, those will by default fall back to the complex case, slowing down operations on that list.

The right detection for copies and copy assignments isn't is_trivial, but is_trivially_copyiable. At the beginning of the thread, I was indeed confused by this; we are conflating multiple independent semantics into the "primitive" / "isComplex" case.

is_trivial implies is_trivially_copyable, see https://en.cppreference.com/w/cpp/types/is_trivial.

Should they be split in *independent* semantics? At least 1/2 are different:

I was thinking about that as well, but that’s more refactoring that I’m willing to do just now before 6.0. Maybe for 6.1?

1) Can be value constructed with memset(0)
 * Primitive: yes by definition
 * Trivial(ly constructible): not in general, see the PDM example
 * Relocatable: not in general

2) Can be copy/move constructed/assigned with memcpy
 * Primitive: yes by definition
 * Trivial(ly copy constructible): yes
 * Relocatable: not in general

3) Can be relocated with memcpy
 * Primitive: yes by definition
 * Trivial(ly copy constructible, destructible): yes
 * Relocatable: yes by definition

4) Can be destroyed by just freeing memory
 * Primitive: yes by definition
 * Trivial(ly destructible): yes
 * Relocatable: not in general

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.

(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.


Language Lawyer Hat: is_trivial is the wrong type trait when it comes to detect trivial copiability anyhow, example:

 struct S { int i; S operator=(const S &)=delete; };

is trivial and not copy assignable. Isn't C++ a fun language to work with... :P

Sigh… is_trival implies is_trivially_copyable. That one implies https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable, which implies that all “eligible” copy/move constructor and assignment operators are trivial. But they don’t disallow deleting them (as that makes the operator not eligible).

So what are the correct traits then? Sounds like “is_trivially_copyable and no deleted copy/move operators” is about what we need :/


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/development/attachments/20201112/2716ea73/attachment.html>

More information about the Development mailing list