How to upcast a QPointer<Descendant>
-
I have declared a class B, and a descendant class D. I also have a method:
myMethod(QPointer<B> param1) {}
When I try to call myMethod() with a QPointer to D as the parameter, the compiler complains that:
cannot convert `QPointer<D>' to 'QPointer<B>'
Why is it complaining? I thought passing a QPointer<D> will implicitly upcast it to QPointer<B>. How should I resolve this?
-
My method will create a singleton which uses a QPointer to the original object, When the method returns, the singleton survives and keeps using that QPointer. If something else in my code deletes the original object, I want to ensure the singleton's QPointer becomes null. So I thought that I must pass QPointer to Qpointer along the call chain to ensure weak/strong references remain intact, so the singleton's QPointer will switch to null when the original object is deleted.
But if I understand the above correct, I can pass QPointer to standard pointer to QPointer, and all of the QPointers will switch to null when the original object is deleted.
@ocgltd said in How to upcast a QPointer<Descendant>:
But if I understand the above correct, I can pass QPointer to standard pointer to QPointer, and all of the QPointers will switch to null when the original object is deleted.
This below says everything you need to know about
QPointer
.A guarded pointer, QPointer<T>, behaves like a normal C++ pointer T *, except that it is automatically cleared when the referenced object is destroyed (unlike normal C++ pointers, which become "dangling pointers" in such cases). T must be a subclass of QObject.
Guarded pointers are useful whenever you need to store a pointer to a QObject that is owned by someone else, and therefore might be destroyed while you still hold a reference to it. You can safely test the pointer for validity.
A guarded pointer will automatically cast to a T *, so you can freely mix guarded and unguarded pointers.
( https://doc.qt.io/qt-6/qpointer.html#details )
Also it's mentioned that
QPointer< T >
is equally-comparable withT *
, so like @Christian-Ehrlicher said, you can use it wherever a pointer is expected.
The convenient bonus is that it's guarded and you can store it without worrying that it might point to free'd memory, because the originalT
obj has been deleted by its owner.
(That's why it only works withQObject
based types)So I thought that I must pass QPointer to Qpointer along the call chain to ensure weak/strong references remain intact, so the singleton's QPointer will switch to null when the original object is deleted.
Shouldn't make any difference.
If you pass/castQPointer<A>
-->A*
-->QPointer<A>
, the 2ndQPointer<A>
is still guarded and watches the lifetime ofA
, since it's created from a pointer toA
and they all three point to the same location.
--> "equally-comparable" ;-)Edit:
In case of future readers:
From looking at the
QPointer
source code, it's easy to see how it works.
For every operation (operators, move/copy/assignment c'tors) the QPointer's internal data is used, which is nothing more than the raw pointer. -
I have declared a class B, and a descendant class D. I also have a method:
myMethod(QPointer<B> param1) {}
When I try to call myMethod() with a QPointer to D as the parameter, the compiler complains that:
cannot convert `QPointer<D>' to 'QPointer<B>'
Why is it complaining? I thought passing a QPointer<D> will implicitly upcast it to QPointer<B>. How should I resolve this?
@ocgltd From the documentation:
"*A guarded pointer will automatically cast to a T *, so you can freely mix guarded and unguarded pointers. This means that if you have a QPointer<QWidget>, you can pass it to a function that requires a QWidget . For this reason, it is of little value to declare functions to take a QPointer as a parameter; just use normal pointers. Use a QPointer when you are storing a pointer over time.". -
From what I've found online this should work as I describe above in Qt6.6 and later (yet it doesn't for me). I've also seen answers to pass qptr.data() to the function - which I can confirm does work. I pass a QPointer to the method because it will create an object with lifespan beyond the return of the method, so are you saying just copy the regular pointer back to QPointer in the method? And if I do so, will all strong/weak references to the underlying object continue to work properly? (Transfer from QPointer to regular pointer to Qpointer)
-
Since QPointer does no refcounting I don't see a problem here but also don't understand your lifespan problem.
-
My method will create a singleton which uses a QPointer to the original object, When the method returns, the singleton survives and keeps using that QPointer. If something else in my code deletes the original object, I want to ensure the singleton's QPointer becomes null. So I thought that I must pass QPointer to Qpointer along the call chain to ensure weak/strong references remain intact, so the singleton's QPointer will switch to null when the original object is deleted.
But if I understand the above correct, I can pass QPointer to standard pointer to QPointer, and all of the QPointers will switch to null when the original object is deleted.
-
My method will create a singleton which uses a QPointer to the original object, When the method returns, the singleton survives and keeps using that QPointer. If something else in my code deletes the original object, I want to ensure the singleton's QPointer becomes null. So I thought that I must pass QPointer to Qpointer along the call chain to ensure weak/strong references remain intact, so the singleton's QPointer will switch to null when the original object is deleted.
But if I understand the above correct, I can pass QPointer to standard pointer to QPointer, and all of the QPointers will switch to null when the original object is deleted.
@ocgltd said in How to upcast a QPointer<Descendant>:
But if I understand the above correct, I can pass QPointer to standard pointer to QPointer, and all of the QPointers will switch to null when the original object is deleted.
This below says everything you need to know about
QPointer
.A guarded pointer, QPointer<T>, behaves like a normal C++ pointer T *, except that it is automatically cleared when the referenced object is destroyed (unlike normal C++ pointers, which become "dangling pointers" in such cases). T must be a subclass of QObject.
Guarded pointers are useful whenever you need to store a pointer to a QObject that is owned by someone else, and therefore might be destroyed while you still hold a reference to it. You can safely test the pointer for validity.
A guarded pointer will automatically cast to a T *, so you can freely mix guarded and unguarded pointers.
( https://doc.qt.io/qt-6/qpointer.html#details )
Also it's mentioned that
QPointer< T >
is equally-comparable withT *
, so like @Christian-Ehrlicher said, you can use it wherever a pointer is expected.
The convenient bonus is that it's guarded and you can store it without worrying that it might point to free'd memory, because the originalT
obj has been deleted by its owner.
(That's why it only works withQObject
based types)So I thought that I must pass QPointer to Qpointer along the call chain to ensure weak/strong references remain intact, so the singleton's QPointer will switch to null when the original object is deleted.
Shouldn't make any difference.
If you pass/castQPointer<A>
-->A*
-->QPointer<A>
, the 2ndQPointer<A>
is still guarded and watches the lifetime ofA
, since it's created from a pointer toA
and they all three point to the same location.
--> "equally-comparable" ;-)Edit:
In case of future readers:
From looking at the
QPointer
source code, it's easy to see how it works.
For every operation (operators, move/copy/assignment c'tors) the QPointer's internal data is used, which is nothing more than the raw pointer. -
O ocgltd has marked this topic as solved on
-
My method will create a singleton which uses a QPointer to the original object, When the method returns, the singleton survives and keeps using that QPointer. If something else in my code deletes the original object, I want to ensure the singleton's QPointer becomes null. So I thought that I must pass QPointer to Qpointer along the call chain to ensure weak/strong references remain intact, so the singleton's QPointer will switch to null when the original object is deleted.
But if I understand the above correct, I can pass QPointer to standard pointer to QPointer, and all of the QPointers will switch to null when the original object is deleted.
@ocgltd said in How to upcast a QPointer<Descendant>:
If something else in my code deletes the original object, I want to ensure the singleton's QPointer becomes null.
You know this is the case if you use a QSharedPointer? Actually if you really want elsewhere's deletion to set your copy to
nullptr
it does not do that, but it is for sharing and delete-on-last-no-reference. So maybe not what you want :) So just mentioning it in case :)QPointer
only allows forQObject
objects, nulling on destruction/destroyed()
.