Details
-
Epic
-
Resolution: Unresolved
-
P3: Somewhat important
-
None
-
None
-
None
-
QIntrusiveSharedPointer
Description
We currently have two smart pointer classes which are deigned to be intrusive shared pointers: QSharedDataPointer and QExplicitlySharedDataPointer.
They're both less than perfect:
- QSharedDataPointer detaches too early, as in
if (d->name == name) // detaches! (but shouldn't) return; d->name = name; // checks ref-count again (pointlessly)
- In Qt 5, even this would detach already: if (d) (fixed in Qt 6)
- it also checks the ref-count on every access
- atomic operation bloat
- needlessly increasing TEXT size and
- acting as powerful optimizer firewalls
- atomic operation bloat
- QExplicitlySharedDataPointer doesn't propagate constness
- while this isn't a-priori expected from a smart pointer, it kind of is from a pimpl_ptr
- has led to race conditions in at least QDateTime
- both classes have a non-explicit operator bool(), which is dangerous, because it enables arithmetic and integer promotion on the result
- both classes also use QAtomicInt's ref()/deref(), which are infamously inefficient:
- ref() is ordered, but could be relaxed (can't be fixed, because it's documented like that)
- deref() is ordered, but would only need an acquire fence when the count drops to zero
Qt prides itself on its backward-compatibility, so we can't fix any of these without breaking user code (the addition of QSharedDataPointer::operator bool() to fix the detach in if (d) probably broke some users already).
The most sensible solution, then, is to introduce a new smart pointer that does not have these problems, and slowly phase out the old classes from Qt code until they can be moved to Qt6Compat come Qt 7.
This is what QIntrusiveSharedPointer sets out to do. An additional design goal is to enable classes that use QIntrusiveSharedPointer to = default all special member functions inline:
- default ctor (sets d = nullptr)
- copy/move ctors
- copy/move assignment operators
- dtor
provided they implement a part of the "Intrusive Protocol" out-of-line:
- qIntrusiveRef()
- qIntrusiveMaybeDelete()
mmutz already started the implementation in 2019: