[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