Early in the Qt 5 development cycle, we had made the decision to deprecate QPointer and replace it with the more modern QWeakPointer. That decision is now reversed, so please continue using QPointer where you were using them. Moreover, don’t use QWeakPointer except in conjunction with QSharedPointer.
To understand the reason behind this back and forth, we need to go back a little in history.
Almost 3 years ago, I wrote a blog about the smart pointer classes in Qt. In that blog, I talked about how QPointer had some broken semantics and how it should be deprecated. I even mentioned that it was slow.
The reason it is slow in Qt 4 is its implementation. It’s a direct descendant of the Qt 3 QGuardedPtr and Whenever you created a QGuardedPtr for a given object, Qt would simply add the pointer and the guard to a global hashing table. In Qt 4, the implementation is the same, except that now it required locking a global mutex. (For those who don’t remember Qt 3, QObject could not be used outside the main thread there).
That means that creating a QPointer in Qt 4 requires locking a global mutex and inserting an item into a global hash, which may involve rehashing depending on how many items it holds. And when that QObject was destroyed, it would need to iterate over the hash and notify all the watchers that the object had died.
With Qt 4.5, I introduced QSharedPointer and QWeakPointer, which are a lot more efficient. The way that those two communicate is by way of a “reference-counted reference-counter”. That is, the private data common to those two classes contains basically two reference counters: the strong and the weak one. The strong counter counts the lifetime of the pointer, where a value of 1 or higher indicates that the object is still alive, whereas a zero indicates that it’s deleted. The weak counter controls the lifetime of the private data itself.
In other words, the strong counter counts how many QSharedPointer objects are attached to this particular pointer, whereas the weak counter counts both QSharedPointer and QWeakPointer instances. So you see how the last QSharedPointer instance being destroyed causes the pointer to be deleted too.
With Qt 4.6, I added a feature that allowed one to use QWeakPointer to track QObject instances directly, without going through QSharedPointer. When trying to figure out how to optimise QPointer, I realised that the “reference-counted reference counter” is the best solution — actually, for tracking without QSharedPointer, a “reference-counted boolean” would be enough, but since we didn’t have QAtomicBool, we regular reference counter would do just fine.
The solution is simple: if you create a the first instance of the guard, it allocates this private block and sets the strong counter to indicate that the object is alive. When the object is deleted, it simply sets the strong counter to zero. The use of the weak counter allows us to share the ownership of this private, so it’s quite fast.
And in Qt 5…
When we started working on Qt 5, it was clear that the previous implementation of QPointer had to go. We don’t want to keep old cruft for another 3-6 years, or however long it’s going to take until we reach Qt 6. But we also promised to maintain source compatibility as much as possible with Qt 4, so we couldn’t just remove the class.
Instead, last November, one developer simply rewrote QPointer on top of QWeakPointer and deprecated it. By keeping the old API and coupling it with the new implementation, we suddenly had a fast QPointer. But the deprecation stayed, because we thought we had “too many smart pointer classes” (see the title of my blog).
In March, when we started to try and clean up the Qt code base of our own deprecated classes, we realised that QPointer is used just about everywhere. Since we had a properly fast implementation, there was actually no good reason to keep generating compiler warnings about the use of that class. That led to QPointer being un-deprecated.
Finally, a month and a half ago, the other shoe dropped. The argument of “too many classes” is not valid if it’s trumping over having proper API and classes that work correctly. What we realised is that overloading QWeakPointer‘s purpose was making its API worse instead, leading to doubts about when to use some of its member functions. Therefore, we deprecated instead QWeakPointer use without QSharedPointer.
That means you should continue using QPointer in your code. Unfortunately, if you’re still targetting Qt 4, it means your code will not be as fast as it could be, but at least it will be clean.
It also means the QWeakPointer::data() member is deprecated and you should not use it.
Qt’s smart pointer classes are neatly grouped now as follows:
|Shared data||QSharedDataPointer, QExplicitlySharedDataPointer||Sharing of data (not of pointers), implicitly and explicitly. Also known as “intrusive pointers”.|
|Thread-safe sharing pointers, like C++11′s std::shared_ptr only with a nice Qt API|
|For RAII usage: takes ownership of a pointer and ensures it is properly deleted at the end of the scope. No sharing.|
|Tracking QObjects||QPointer||Tracks the lifetime of a given QObject instance|