[Development] QIntrusiveSharedPointer (was: Re: atomic reference counting implementation)
Mutz, Marc
marc at kdab.com
Wed Aug 7 22:09:54 CEST 2019
On 2019-08-07 22:01, Konstantin Tokarev wrote:
> It would be even better if it was possible to choose type of reference
> counting,
> e.g. via template parameter. In many cases atomic counters are not
> needed
> and just reduce performance.
On 2019-08-07 21:46, Philippe wrote:
> On Wed, 07 Aug 2019 21:00:30 +0300
> "Mutz, Marc" <marc at kdab.com> wrote:
[...]
>>> I think I'm on record saying such impl details as ref-counting for Qt
>>> implicitly shared classes
>>> should not be public API. This is a perfect example of why I believe
>>> that to be fundamentally true.
>
> +1
I have just uploaded my proposed solution for this:
QIntrusiveSharedPointer. Even though I didn't have a) taking Qt pimpl
private and b) allowing non-atomic ref counts use-cases in mind when I
designed it, it supports these use-cases out of the box. I think its
design will satisfy all the constraints, even though I'd like to see a
round of internal use first (5.14, or, more likely by now 5.15, make
public in Qt 6):
- provide a public replacement for
QSharedDataPointer/QExplicitlySharedDataPointer with all their (known)
shortcomings fixed
while at the same time:
- allow Qt to use it's own private reference counting (by having
qshareddatav2_p.h and the Intrusive Protocol implemented like for
QSharedData); I haven't implemented a QSDV2, yet, but off the top of my
head the ref-counting is always out-of-line, so it's possible to
retrofit it into already-released classes
- allow users to use a simple int as ref-count
This is an evolution of
https://codereview.qt-project.org/c/qt/qtbase/+/115213 and it has all
the benefits of QtPrivate::SharedDataPointer to, to wit:
- it's possible to have an inline move ctor:
just need to export an out-of-line overload of
qIntrusiveDeref(QXXXPrivate*), which can call
qIntrusiveDeref<QXXXPrivate>() if Private is derived from a supported
QSharedData-alike
- in the same way, even the dtor can be inline
- it's even possible to have all special member functions = default'ed
by exporting qIntrusiveRef() in addition. This reduces the number of DLL
entry points from 4 (default, copy ctor/assignment op, dtor) to two
(qIntrusive(De)ref()).
- const propagating
- explicit detach
- proper conversion to bool (unlike QSDP, which detaches, making every
if (mutable d) tautological)
It also adds
- constexpr default ctor and ctor from nullptr
- implicit ctor from nullptr (but explicit from T*)
Which means that on conforming compilers (not MSVC) a static QISP
init'ed to nullptr will be placed into the BSS segment and not cause
dynamic initialisation (even if the dtor is not trivial - the std::mutex
principle).
The only drawback over QtPrivate::SharedDataPointer is that you need to
manually declare and implement qIntrusiveRef() and qIntrusiveDeref(); we
can't hide it in (one) macro. But I think that's a benefit. It reduces
the number of DLL entry points over the static-Public-member-functions
design of QtP::SDP, which is probably the reason it consistently
produces less executable code than QSDP, QESDP and not more code than
QtP::SDP did (which sometimes, e.g. for QCommandLineArgument, increased
text size a bit).
Flame away...
Thanks,
Marc
More information about the Development
mailing list