Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Is there any cases where QObject will not emit a destroyed signal?



  • I have a situation where it's absolutely critical that I known when an object is destroyed. No matter how or when it happens. Since it's so critical that I know, I wanted to know if there are any edge cases where QObject will not emit the destroyed signal upon being destroyed. Has anyone encountered any edge cases like this? https://myip.kim/ https://birthdaywishes.onl/ https://elecpay.in/tneb/


  • Moderators

    @MalachiCole
    there shouldn't be. If you take a look at the source code:

    
    935	QObject::~QObject()
    936	{
    937	    Q_D(QObject);
    938	    d->wasDeleted = true;
    939	    d->blockSig = 0; // unblock signals so we always emit destroyed()
    940	
    941	    QtSharedPointer::ExternalRefCountData *sharedRefcount = d->sharedRefcount.loadRelaxed();
    942	    if (sharedRefcount) {
    943	        if (sharedRefcount->strongref.loadRelaxed() > 0) {
    944	            qWarning("QObject: shared QObject was deleted directly. The program is malformed and may crash.");
    945	            // but continue deleting, it's too late to stop anyway
    946	        }
    947	
    948	        // indicate to all QWeakPointers that this QObject has now been deleted
    949	        sharedRefcount->strongref.storeRelaxed(0);
    950	        if (!sharedRefcount->weakref.deref())
    951	            delete sharedRefcount;
    952	    }
    953	
    954	    if (!d->isWidget && d->isSignalConnected(0)) {
    955	        emit destroyed(this);
    956	    }
    957	
    958	    if (d->declarativeData) {
    959	        if (static_cast<QAbstractDeclarativeDataImpl*>(d->declarativeData)->ownedByQml1) {
    960	            if (QAbstractDeclarativeData::destroyed_qml1)
    961	                QAbstractDeclarativeData::destroyed_qml1(d->declarativeData, this);
    962	        } else {
    963	            if (QAbstractDeclarativeData::destroyed)
    964	                QAbstractDeclarativeData::destroyed(d->declarativeData, this);
    965	        }
    966	    }
    967	
    968	    QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
    969	    if (cd) {
    970	        if (cd->currentSender) {
    971	            cd->currentSender->receiverDeleted();
    972	            cd->currentSender = nullptr;
    973	        }
    974	
    975	        QBasicMutex *signalSlotMutex = signalSlotLock(this);
    976	        QBasicMutexLocker locker(signalSlotMutex);
    977	
    978	        // disconnect all receivers
    979	        int receiverCount = cd->signalVectorCount();
    980	        for (int signal = -1; signal < receiverCount; ++signal) {
    981	            QObjectPrivate::ConnectionList &connectionList = cd->connectionsForSignal(signal);
    982	
    983	            while (QObjectPrivate::Connection *c = connectionList.first.loadRelaxed()) {
    984	                Q_ASSERT(c->receiver.loadAcquire());
    985	
    986	                QBasicMutex *m = signalSlotLock(c->receiver.loadRelaxed());
    987	                bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
    988	                if (c->receiver.loadAcquire()) {
    989	                    cd->removeConnection(c);
    990	                    Q_ASSERT(connectionList.first.loadRelaxed() != c);
    991	                }
    992	                if (needToUnlock)
    993	                    m->unlock();
    994	            }
    995	        }
    996	
    997	        /* Disconnect all senders:
    998	         */
    999	        while (QObjectPrivate::Connection *node = cd->senders) {
    1000	            Q_ASSERT(node->receiver.loadAcquire());
    1001	            QObject *sender = node->sender;
    1002	            // Send disconnectNotify before removing the connection from sender's connection list.
    1003	            // This ensures any eventual destructor of sender will block on getting receiver's lock
    1004	            // and not finish until we release it.
    1005	            sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), node->signal_index));
    1006	            QBasicMutex *m = signalSlotLock(sender);
    1007	            bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
    1008	            //the node has maybe been removed while the mutex was unlocked in relock?
    1009	            if (node != cd->senders) {
    1010	                // We hold the wrong mutex
    1011	                Q_ASSERT(needToUnlock);
    1012	                m->unlock();
    1013	                continue;
    1014	            }
    1015	
    1016	            QObjectPrivate::ConnectionData *senderData = sender->d_func()->connections.loadRelaxed();
    1017	            Q_ASSERT(senderData);
    1018	
    1019	            QtPrivate::QSlotObjectBase *slotObj = nullptr;
    1020	            if (node->isSlotObject) {
    1021	                slotObj = node->slotObj;
    1022	                node->isSlotObject = false;
    1023	            }
    1024	
    1025	            senderData->removeConnection(node);
    1026	            if (needToUnlock)
    1027	                m->unlock();
    1028	
    1029	            if (slotObj) {
    1030	                locker.unlock();
    1031	                slotObj->destroyIfLastRef();
    1032	                locker.relock();
    1033	            }
    1034	        }
    1035	
    1036	        // invalidate all connections on the object and make sure
    1037	        // activate() will skip them
    1038	        cd->currentConnectionId.storeRelaxed(0);
    1039	    }
    1040	    if (cd && !cd->ref.deref())
    1041	        delete cd;
    1042	    d->connections.storeRelaxed(nullptr);
    1043	
    1044	    if (!d->children.isEmpty())
    1045	        d->deleteChildren();
    1046	
    1047	#if QT_VERSION < 0x60000
    1048	    qt_removeObject(this);
    1049	#endif
    1050	    if (Q_UNLIKELY(qtHookData[QHooks::RemoveQObject]))
    1051	        reinterpret_cast<QHooks::RemoveQObjectCallback>(qtHookData[QHooks::RemoveQObject])(this);
    1052	
    1053	    Q_TRACE(QObject_dtor, this);
    1054	
    1055	    if (d->parent)        // remove it from parent object
    1056	        d->setParent_helper(0);
    1057	}
    

    you will see, that even if you have set blockSignals to true, the destroyed signal will be emitted.



  • @J-Hilk , @MalachiCole
    I haven't read through the code, and don't know what exactly it calls, but since the OP asks about "edge case" and "absolutely critical", is there any kind of indirect dynamic memory allocation going on here at all? Just that it always possible that the application runs out of memory while executing the code, a slight possibility to be aware of. No more than that.


Log in to reply