[Development] Not delivering signals to slots in class sub-objects already destroyed
Thiago Macieira
thiago.macieira at intel.com
Fri Sep 5 02:08:47 CEST 2025
On Thursday, 4 September 2025 14:41:14 Pacific Daylight Time Thiago Macieira
wrote:
> On Tuesday, 2 September 2025 22:18:54 Pacific Daylight Time Thiago Macieira
>
> wrote:
> > a) should this functionality be provided at all?
> > b) should it be provided by default for PMFs? [*]
> > c) if it's provided for PMFs, should they be allowed to opt out?
> > d) should it be provided by default for callbacks other than PMFs?
> > e) if there's a flag to opt in or out, what do we call the
> > Qt::XxxConnection?
>
> Still need a discussion on the above, with the default-for-PMF maybe
> depending on an analysis of the overhead.
>
> Right now, I'm leaning towards:
> a) yes
> b) yes
> c) no
> d) no
> e) probably Qt::ReceiverMetaObjectBoundConnection to opt-in
If we decided that the answer to (d) was "yes" (enable by default for non-
PMFs), we could make it so one can extend the lifetime by casting the receiver
object to an earlier class, such as QObject itself. The example I gave of
Q_APPLICATION_STATIC would become:
QObject::connect(app, &QObject::destroyed, static_cast<QObject *>(app),
reset, Qt::DirectConnection);
If we were designing this functionality *now*, that's how I'd do it.
Unfortunately, this is not a green field scenario and changing the behaviour
now causes breakages, such as Q_APPLICATION_STATIC and a few others in the
patch linked in the OP. The CI is also failing in the QRangeModel test for no
reason that I can tell, so it's possible the problem is more widespread than
the few issues I've already caught.
That's why I am thinking the answer to (d) must be "no".
We could make it a compile-time opt-in per .cpp file, so code ported to the new
behaviour can be marked safe, and we could then flip the default come Qt 7 or
8. But I don't think it's worth it.
Instead, I'd like to introduce a different feature, allowing the slot's first
argument to be a pointer to the receiver class. So the qmenu.cpp example would
become:
QObject::connect(menuAction, &QAction::changed, q, [](QMenu *q) {
QMenuPrivate *d = q->d_func();
if (!d->tornPopup.isNull())
d->tornPopup->updateWindowTitle();
});
With this, the lambda has become stateless, without the need to store
information the QObject Connection already possesses *and* passes to the
QCallableObject. And since we know the receiver must be a QMenu, if the QMenu
destructor has finished, the slot cannot be invoked. The code to detect this
situation is identical to the PMF one, though it could also just be in the
template code.
PS: I don't know yet how to make this detection. I may resort to concepts and
make the feature C++20-only.
--
Thiago Macieira - thiago.macieira (AT) intel.com
Principal Engineer - Intel Platform Engineering Group
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 5150 bytes
Desc: not available
URL: <http://lists.qt-project.org/pipermail/development/attachments/20250904/41885e9e/attachment.bin>
More information about the Development
mailing list