Hi, On 11/11/2020 18:14, Thiago Macieira wrote:
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.
The problem is that ~100% of our value classes are not trivial, because we always initialize our data members. So, we need type traits anyhow to distinguish between primitive/relocatable/complex; and I am against calling it "Q_TRIVIAL_TYPE" because this property has now nothing to do with pure triviality.
*Some* trivial types can be initialized via memset(0), but not all of them, so the set of primitive types (according to our current definition) and the set trivial types are intersecting (*).
In theory we could just rely on the optimizer to turn std::uninitialized_value_construct_n into a memset(0). (If you have an out of line constructor that does 0-bit initialization, and the compiler doesn't see it and do the transformation, you don't have my sympathies.)
This would, in principle, allow for unifying handling of primitive and relocatable types:
* Construction: use uninitialized_value_construct * Primitive: the compiler figures out it's a memset()* Relocatable: call the default constructor (and possibly the compiler figures out it's a memset())
* Copy: just use std::uninitialized_copy * Primitive: the compiler figures out it's a memcpy()* Relocatable: call the copy constructor (possibly the compiler figures out it's a memcpy())
* Move: just use std::uninitialized_copy * Primitive: the compiler figures out it's a memcpy()* Relocatable: call the move constructor (possibly the compiler figures out it's a memcpy())
* Relocation (destructive move): use memcpy * Primitive: we know it works * Relocatable: we know it works * Destruction: just use std::destroy * Primitive: compiler does nothing * Relocatable: call the destructors (possibly do nothing if trivial)But as far as I can tell, compilers do not do these transformations as aggressively as we'd like. So we still have a distinct advantage at using the trait, at least for the Qt 6 lifetime. Take for instance QStringView:
https://gcc.godbolt.org/z/6Taoo4
GCC, ICC, MSVC don't optimize anything. Clang chokes on the (pointer,int) scenario, but only if the initialization goes through a constructor. Don't ask me why.
(*) Properly intersecting, in the sense that here are primitive types that are not trivial (all/most the Q_PRIMITIVE_TYPE in Qt), and trivial types that are not primitive (the aforementioned class with pointers to data members).
My 2 c, -- Giuseppe D'Angelo | giuseppe.dang...@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
smime.p7s
Description: S/MIME Cryptographic Signature
_______________________________________________ Development mailing list Development@qt-project.org https://lists.qt-project.org/listinfo/development