Initialization of QSharedDataPointer's for empty objects (i.e. Foo::Foo(void))

Thiago Macieira thiago at kde.org
Mon Apr 29 23:16:29 BST 2013


On segunda-feira, 29 de abril de 2013 21.52.37, Milian Wolff wrote:
> I.e.: In the ctors that construct an "empty" object do not call "new
> Private" but instead (re-)use a static shared empty object created on the
> stack - see shared_empty and shared_null in qstring.{cpp,h}.

You probably did not mean what you said: you do not want something allocated 
on the stack. You want a global. Like QString :-)

To be *really* like QString, you want your private to be POD. That means you 
cannot derive from QSharedData, you cannot use QAtomicInt, QString or 
QByteArray. That may be taking it a bit too far.

If your private class is not POD, you should use a K/Q_GLOBAL_STATIC instead 
to hold your private. Examples:

corelib/mimetypes/qmimedatabase.cpp:Q_GLOBAL_STATIC(QMimeDatabasePrivate, 
staticQMimeDatabase)
corelib/tools/qlocale_win.cpp:Q_GLOBAL_STATIC(QSystemLocalePrivate, 
systemLocalePrivate)
gui/text/qfontdatabase.cpp:Q_GLOBAL_STATIC(QFontDatabasePrivate, privateDb)
network/access/qabstractnetworkcache.cpp:Q_GLOBAL_STATIC(QNetworkCacheMetaDataPrivate, 
metadata_shared_invalid)
plugins/bearer/qnetworksession_impl.cpp:Q_GLOBAL_STATIC(QNetworkSessionManagerPrivate, 
sessionManager);
sql/kernel/qsqlquery.cpp:Q_GLOBAL_STATIC_WITH_ARGS(QSqlQueryPrivate, 
nullQueryPrivate, (0))

> I do wonder though why QString has both, a shared_empty and a shared_null
> object. A single one should suffice for most objects, no?

	QString().isNull() == true
	QString("").isNull() == false

> Does anyone have any experience with this? Are there any pitfalls or
> downsides to the approach taken by QString? I also thought about not
> initializing the QSaredDataPointer at all but that would require a lot of
> additional code when its being used to ensure its only accessed when it is
> initialized. I think the pattern applied in QString is much nicer in that
> regard.

It is, but the pattern of having a null d pointer also exists elsewhere in Qt.

For example, in QUrl, it's implemented manually. But there are also a few 
examples of doing that with QSharedDataPointer.

Take a look at QNetworkProxy or QUrlQuery:
template<> void QSharedDataPointer<QNetworkProxyPrivate>::detach()
{
    if (d && d->ref.load() == 1)
        return;
    QNetworkProxyPrivate *x = (d ? new QNetworkProxyPrivate(*d)
                               : new QNetworkProxyPrivate);
    x->ref.ref();
    if (d && !d->ref.deref())
        delete d;
    d = x;
}

And then:
QNetworkProxy::ProxyType QNetworkProxy::type() const
{
    return d ? d->type : DefaultProxy;
}

-- 
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center
      PGP/GPG: 0x6EF45358; fingerprint:
      E067 918B B660 DBD1 105C  966C 33F5 F005 6EF4 5358
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 190 bytes
Desc: This is a digitally signed message part.
URL: <http://mail.kde.org/pipermail/kde-core-devel/attachments/20130429/e9cd2aef/attachment.sig>


More information about the kde-core-devel mailing list