[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