[Development] Meaning of Q_PRIMITIVE_TYPE?
Jedrzej Nowacki
jedrzej.nowacki at nokia.com
Fri Mar 30 16:54:09 CEST 2012
On Friday 30. March 2012 13.54.06 ext Marc Mutz wrote:
> On Friday March 30 2012, Jedrzej Nowacki wrote:
> > On Wednesday 28. March 2012 15.37.46 ext Marc Mutz wrote:
> > > Hi,
> > >
> > > Over at http://codereview.qt-project.org/21518, we're discussing
> > > whether QUuid is Q_PRIMITIVE_TYPE or only Q_MOVABLE_TYPE.
> > >
> > > The documentation of Q_DECLARE_TYPEINFO says Q_PRIMITIVE_TYPE means the
> > > type is a POD, without constructors or destructors. According to that
> > > definition, QUuid is not primitive. But neither would be QFixed and
> > > QFlags, which have been marked primitive in the past.
> > >
> > > I think the intention of Q_PRIMITIVE_TYPE, and the way it is used in
> > > Qt, is to mark types that act as ints do, ie. there's no class
> > > invariant, so char[sizeof(type)] = { 0 } is equal to the
> > > default-constructed value, uninitialised memory represents a valid
> > > value[1], and the object owns no resources. It is in this sense that
> > > QFixed, QFlags and QUuid are primitive types.
> > >
> > > [1] This doesn't hold for cups_option_t, btw, which is marked
> > > primitive, but is a struct{char*a,*b;}, so uninitialised memory does
> > > not represent a valid value, even though, technically, it's a POD.
> > >
> > > So I'd like to propose to extend the scope of Q_PRIMITIVE_TYPE to cover
> > > such non-POD classes that are nevertheless close enough to PODs.
> > >
> > > That means:
> > > 1a. memset(0, &t, sizeof(T)) constructs a valid object, and that object
> > > is equal to T(), if T has a default constructor.
> > > -alternatively-
> > > 1b Any bit pattern represents a valid object (one that the dtor can be
> > > called on).
> > > 2. memcpy() creates a valid independent copy of the object
> > > 3. The dtor doesn't need to be run.
> > >
> > > With 1a+2+3, primitiveness is a strict superset of PODness.
> > >
> > > If Jędrzej is right, though, and the intent was for primitive types to
> > > not require initialisation, ie. the 1b alternative is used, PODness is
> > > no longer sufficient for primitiveness. And cups_option_t must be
> > > downgraded to movable.
> > >
> > > Looking at existing usage, I think 1a+2+3 comes closest to what
> > > everyone thinks primitive types mean, so I'd like to update the docs
> > > accordingly.
> > >
> > > Opinions?
> > >
> > > Thanks,
> > > Marc
> >
> > Hi,
> >
> > I think that intent for primitive types was to mark POD types as docs
> >
> > say.
> >
> > By removing '1b' requirement you will break or slowdown code that relays
> >
> > on that feature. For example:
> > - QVarLengthArray - checkout docs for resize() -> not fixable, you need
> > to accept slowdown (memset call)
> > - QVariant - qvariant_p.h isNull detection -> fixable
> >
> > The main problem appears when a "default" constructed value or
> >
> > uninitialized value has to be created.
> >
> > As I said on the gerrit change, what you really need is something like
> >
> > canBeConstructedByMemsetItToZero :-)
>
> Thanks for the QVarLengthArray use-case. Yes, that requires 1b.
>
> I don't mind 1b. Both 1a and 1b definitions make QUuid primitive (which is
> where this discussion started). Since pointers are primitive and thus not
> initialised by QVarLengthArray, I'd be ok even with cups_option_t (pair of
> pointers) staying primitive.
>
> So, does that mean you'll retract your -1?
>
> Thanks,
> Marc
Then the only real problem I see is:
QVarLengthArray<QUuid> array;
array.resize(1);
currently this is always true:
array.at(0).isNull() == QUuid().isNull()
with new definition it may be something else. It is not big deal, just is a bit
unintuitive but if you take QFlags instead QUuid then it may break existing
code in a nasty way, for example:
QVarLengthArray<QFlags> array(1);
...
array[0] |= MyFlag;
How an user of QFlags can know if it is marked as primitive or not? The class
has a ctor so from c++ perspective it is not a POD. Should he check source
code? We do not have documentation for such things and searching for QTypeInfo
specialization is not an option (it may placed everywhere and hidden in a
macro). Dumping values of QTypeInfo<QFlags>, which is internal, is not nice.
So how can he be safe in this case? Only by reinitializing values again:
QVarLengthArray<QFlags> array(1);
array[0] = QFlags();
...
array[0] |= MyFlag;
So I'm afraid that marking QFlags as primitive may decrease performance in
global picture. I believe that it is not a nice API. I will keep my -1 because
it is what I think about it. In the end, you can always override it, I'm fine
with that ;-)
Cheers,
Jędrek
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/development/attachments/20120330/e10dbbf1/attachment.html>
More information about the Development
mailing list