[Interest] QExplictlySharedDataPointer vs QSharedPointer

Elvis Stansvik elvstone at gmail.com
Sat Sep 10 21:17:53 CEST 2016


2016-09-09 1:49 GMT+02:00 Thiago Macieira <thiago.macieira at intel.com>:
> On quinta-feira, 8 de setembro de 2016 21:08:37 PDT Elvis Stansvik wrote:
>> > QESDP doesn't actually require that you derive from QSharedData,
>> > only that you have an atomic integer called "ref" in your structure.
>>
>> I see, that makes sense. And I see now that that's really all that
>> QSharedData brings, the ref member.
>
> Well, it does make the copy constructor private, so that you don't
> accidentally copy your shared data outside of the Q(E)SDP, thus accidentally
> copying the refcounter when it wasn't 1.

Ah, right.

>
>> >> In short, I fail to see a strong use case for QESDP compared to using
>> >> a QSharedPointer. I'm probably missing something.
>> >
>> > The fact that it's a smart pointer, not a raw one.
>>
>> This I don't quite understand. Aren't they both smart pointers? They
>> still seem quite similar to me. The difference mainly seems to be the
>> slightly different API, and where the refcount is stored
>> (external/internal).
>
> Yes, but I wasn't comparing those two. I was comparing the use of a smart
> pointer to not using one.

Ah, sorry. Since I was contrasting QSDP and QSharedPointer, I thought
you were comparing them.

> QESDP has a very limited use-case, as you've
> noticed. It's mostly used so you don't need to do the reference counting
> manually, like the older Qt classes do (QString, for example).

I see.

>
> I also realise I was probably thinking of the even simpler QScopedPointer
> class.
>
>> >> Does anyone know of a code base that makes liberal use of QESDP, or
>> >> could you share how you're making use of it? It's easy to find uses
>> >> for the implicit variant (QISDP).
>> >
>> > qtxmlpatterns, I believe.
>>
>> Thanks, I'll have a look at that and see how it's put to use there.
>
> Not very well. In fact, it's an abuse of QESDP, so don't take it as a good
> example. I created QSharedPointer *because* qtxmlpatterns was abusing QESDP.

Okay, good to know.

>
>> With the above I was mainly looking for design advise: E.g. like when
>> would I choose to use QESDP vs QSDP, and when I would use QSP instead
>> of QESDP. I had also heard on IRC that some people preferred to always
>> work with QESDP instead of QSDP, thinking the lack of control with
>> QSDP was "dangerous", so was looking for opinions on that.
>
> There are advantages for both QSDP and QESDP. It just depends on how often
> your code requires detaching. Take QDateTime as an example (before Qt 5.8).
> QSDP allows for easy detaching when necessary and allows you to write code as
> if you had a regular, raw pointer:
>
> This doesn't detach:
> bool QDateTime::isValid() const
> {
>     return (d->isValidDateTime());
> }
>
> This detaches:
> void QDateTime::setDate(const QDate &date)
> {
>     d->setDateTime(date, time());
> }
>
> On the other hand, non-const non-simple functions could make the one serious
> mistake of QSDP. There's only one case in QDateTime but it's not obvious, so
> here's an example of the mistake from QTextCursor:
>
> void QTextCursor::setKeepPositionOnInsert(bool b)
> {
>     if (d)
>         d->keepPositionOnInsert = b;
> }
>
> The "if (d)" function makes a call to QSharedDataPointer::operator T*(), which
> detaches. The next line calls QSharedPointer::operator->(), which again tries
> to detach, even though we know (by construction) that the reference count is 1
> and there's no need to detach again. The compiler has no way of knowing that,
> so it generates code that will never be executed and a comparison whose result
> we already know.[1]
>
> If we used QESDP, instead, we'd control exactly when to detach and, more
> importantly, when *not* to attempt to detach. On the other hand, you may make
> a mistake and forget to detach somewhere.
>
> The solution we've found is to make QSDP detach explicitly and then never
> again. You can see this in QDateTime (before 5.8) and in QDir: many setter
> functions had code like
>
>     QDateTimePrivate *d = this->d.data(); // detaches (and shadows d)
>
> which causes a detach and then shadows the d variable so that further uses of
> d-> now use the raw pointer.
>
> [1] This is also the most common problem with implicitly-detaching container
> classes in Qt. If you have a QString and do str[0] = 'a'; str[1] = 'b';, the
> code for detaching is present twice, even though we know by construction that
> the second one is not necessary.

Thanks a lot for these examples/gotchas!

Elvis

> --
> Thiago Macieira - thiago.macieira (AT) intel.com
>   Software Architect - Intel Open Source Technology Center
>
> _______________________________________________
> Interest mailing list
> Interest at qt-project.org
> http://lists.qt-project.org/mailman/listinfo/interest



More information about the Interest mailing list