I am currently wondering how to reasonably use the QObject::destroyed(QObject*)
signal.
I noticed that QWidget
-derived objects are treated slightly different. Consider the following small self-contained and compiling example:
/* sscce.pro:
QT += core gui widgets
CONFIG += c++11
TARGET = sscce
TEMPLATE = app
SOURCES += main.cpp
*/
#include <QApplication>
#include <QPushButton>
#include <QTimer>
#include <QtDebug>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QPushButton *button = new QPushButton;
QObject::connect(button, &QPushButton::destroyed,
[=](QObject *o) { qDebug() << o; });
delete button;
QTimer *timer = new QTimer;
QObject::connect(timer, &QTimer::destroyed,
[=](QObject *o) { qDebug() << o; });
delete timer;
return app.exec();
}
This is its output:
QWidget(0x1e9e1e0) QObject(0x1e5c530)
So presumably, the signal is emitted from QObject
's d-tor, so only the QObject
base remains when the slot is called for the QTimer
. However, QWidget
's d-tor seems to intercept as it still identifies itself as a QWidget
from the slot.
Let's assume we have a timer pool that organizes a couple of timers in a QList<QTimer *>
:
struct Pool {
QTimer *getTimer() {
return timers.at(/* some clever logic here */);
}
QList<QTimer *> timers;
};
Now an incautious user might delete the timer that was borrowed to him/her. Well, we can react and simply remove that timer from the list. A slot will do the trick:
Pool::Pool() {
/* for each timer created */
connect(theTimer, SIGNAL(destroyed(QObject*),
this, SLOT(timerDestroyed(QObject*));
}
void Pool::timerDeleted(QObject *object) {
QTimer *theTimer = /* hrm. */
timers.removeOne(theTimer);
}
But what now? Hrm. When the slot is called, the QTimer
already is in destruction and partially destroyed - only its QObject
base remains. So I objously cannot qobject_cast<QTimer *>(object)
.
To resolve this issue, I could think of the following tricks:
QObject
s in the list. Then I'd have to downcast every time I use an item from the list. This could be done using static_cast
, though, as I know there will only be QTimer
s in the list, so no need for dynamic_cast
or qobject_cast
.removeOne
traverse the list using an iterator
and then compare each QTimer
item directly to the QObject
. Then use QList::erase
or such.static_cast
or even reinterpret_cast
the QObject
to a Qtimer
nonetheless.What should I do?
Thank you, merry christmas and happy new year :-)[*]
[*]: Will clean this up when this question is done.
If you're looking for tricks, you could simply use the base QObject objectName and remove the destroyed timer based on that.
It seems clear that your problem is one of object ownership; in particular, how to convey who is responsible for destroying an object. If your Pool object owns the QTimer objects (and thus the user should not delete
them), make it clear through the interface, for example returning a QTimer&
instead of a QTimer*
from your getTimer method. I'm not really well versed in Qt, but if you actually wanted to transmit ownership of the object returned from a method and thus make the user responsible of its deletion, you'd likely return a std::unique_ptr<QTimer>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With