Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Is there any cases where QObject will not emit a destroyed signal?
Forum Updated to NodeBB v4.3 + New Features

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

Scheduled Pinned Locked Moved Unsolved General and Desktop
3 Posts 3 Posters 902 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    MalachiCole
    Banned
    wrote on last edited by VRonin
    #1

    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?

    Edit: [VRonin] removed links

    J.HilkJ 1 Reply Last reply
    0
    • M MalachiCole

      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?

      Edit: [VRonin] removed links

      J.HilkJ Offline
      J.HilkJ Offline
      J.Hilk
      Moderators
      wrote on last edited by J.Hilk
      #2

      @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.


      Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


      Q: What's that?
      A: It's blue light.
      Q: What does it do?
      A: It turns blue.

      JonBJ 1 Reply Last reply
      3
      • J.HilkJ J.Hilk

        @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.

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by JonB
        #3

        @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.

        1 Reply Last reply
        1

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved