Details
-
Bug
-
Resolution: Fixed
-
P3: Somewhat important
-
6.5
-
None
-
e8f5f2031 (dev), 6ed299f72 (6.5)
Description
I'm dropping this as a "do not forget" note.
The QMetaType::NeedsConstruction flag is set for a type T based on this condition:
kernel/qmetatype.h:1254: | (!std::is_trivially_default_constructible_v<T> ? QMetaType::NeedsConstruction : 0)
Which is then used as a check to determine how to "default construct" instances (technically: value construct). If a type does not need construction, it's initialized via memset(0):
inline bool isDefaultConstructible(const QtPrivate::QMetaTypeInterface *iface) noexcept { return checkMetaTypeFlagOrPointer(iface, iface->defaultCtr, QMetaType::NeedsConstruction); } inline void defaultConstruct(const QtPrivate::QMetaTypeInterface *iface, void *where) { Q_ASSERT(isDefaultConstructible(iface)); if (iface->defaultCtr) iface->defaultCtr(iface, where); else memset(where, 0, iface->size); }
And this is documented here:
\value NeedsConstruction This type has a non-trivial default constructor. If the flag is not set, instances can be safely initialized with memset to 0.
This doesn't work in the general case. The Itanium ABI mandates that null pointers to data members must be initialized to -1 https://itanium-cxx-abi.github.io/cxx-abi/abi.html#data-member-pointers . Something like this:
struct X { int X::*ptr; };
is a trivial type but will be incorrectly value-initialized.
There doesn't seem to be a viable trait to know if we can 0-init a trivially constructible class, and we've decided that PRIMITIVE_TYPE isn't that trait either. So the NeedsConstruction logic/shortcut needs fundamentally to be dropped; always call a constructor.