深入理解QT的SIGNAL\SLOT機制(四):Connection結構

書接上文,本章講述connection結構,這部分是信號和槽能發揮作用的核心部分,先來看兩個結構體:

 struct Connection
    {
        QObject *sender;//信號發起者
        QObject *receiver;//信號接收者
        union {
            StaticMetaCallFunction callFunction;//接受者的static_meatcall函數地址
            QtPrivate::QSlotObjectBase *slotObj;
        };
        Connection *nextConnectionList;//以下三個域是用於連接
        Connection *next;
        Connection **prev;
       ...//省略
    };
    // ConnectionList is a singly-linked list
    struct ConnectionList {
        ConnectionList() : first(0), last(0) {}
        Connection *first;
        Connection *last;
    };

用一張圖來表示:
這裏寫圖片描述
在第三章的QMetaObjectPrivate::connect函數中3314行:
QObjectPrivate::get(s)->addConnection(signal_index, c.data());
我們根據s(也就是sender,本例中就是MyWidget對象),拿到s的實例,然後調用該實例的addConnection方法,將connection對象插入到connectionLists列表中。
這裏詳細講解以下addConnection391~405行:
這裏寫圖片描述
391行:我們看到在connectionLists中查找具體的信號是按照下標查找的,所以時間複雜度O(1),我們的mysignal是存儲在0的位置,也就是說,每隔信號的index就是存儲在connectionLists中的位置,所以QObject::connect方法中要確定每隔信號的signal_index。
392-395行:是在操作具有首尾指針的單鏈表。
399行:每次插入之後要清空無用的connection,以保證鏈表中的所有connection都是有用的。

 void QObjectPrivate::cleanConnectionLists()
{
    if (connectionLists->dirty && !connectionLists->inUse) {
        // remove broken connections
        for (int signal = -1; signal < connectionLists->count(); ++signal) {
            QObjectPrivate::ConnectionList &connectionList =
                (*connectionLists)[signal];

            // Set to the last entry in the connection list that was *not*
            // deleted.  This is needed to update the list's last pointer
            // at the end of the cleanup.
            QObjectPrivate::Connection *last = 0;

            QObjectPrivate::Connection **prev = &connectionList.first;
            QObjectPrivate::Connection *c = *prev;
            while (c) {
                if (c->receiver) {
                    last = c;
                    prev = &c->nextConnectionList;
                    c = *prev;
                } else {
                    QObjectPrivate::Connection *next = c->nextConnectionList;
                    *prev = next;
                    c->deref();
                    c = next;
                }
            }

            // Correct the connection list's last pointer.
            // As conectionList.last could equal last, this could be a noop
            connectionList.last = last;
        }
        connectionLists->dirty = false;
    }
}

這段代碼就是去遍歷connectionLists,檢查每隔信號的dirty和inUse屬性,dirty表示disconnected,但是connection對象還存在,所以應該刪除,inUse是connect的引用計數,也就是說,如果當前connectionList對象已經不用,就要刪除。如果connection的receiver不空,保留,爲空,刪除。
繼續來看connect函數:
401行: c->prev = &(QObjectPrivate::get(c->receiver)->senders);
根據receiver拿到實體類,在拿到senders,這個senders不是發送者,是接受者的鏈表,是用來刪除的,也就是最上面圖結構的senders,一旦接受者被析構,這個接受者的鏈表會被依次刪除。
402~405行:操作鏈表,不在贅述。
到此爲止可以說把QObject::connect函數說完了,看明白的童鞋應該會理解我在一開始說的觀察者模式了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章