2014-05-12 38 views
0

如果我發送帶有對象引用的信號,是否有任何形式的保證,這些插槽將在對象遭受其他部件更改之前處理信號的程序?Qt,將參考信號作爲信號發送時的數據完整性

或者我必須發送信號的深層副本,以確保信號?

+0

當您發送參考與信號一個對象,它被傳遞無論如何:http://qt-project.org/doc/qt-4.8/qmetaobject.html#normalizedSignature。 – vahancho

+0

您應該考慮使用[Qt隱式數據共享](http://qt-project.org/doc/qt-5/implicit-sharing.html),就像Qt容器,'QString'和許多其他Qt數據類一樣。這與Qt信號和插槽一起運行良好。它可能不值得你的用例,但很高興知道它是可能的並且相對容易。 – hyde

+0

@vahancho「當你發送一個帶有信號的對象的引用時,它就會作爲一個副本被傳送」**不,它不是**。至少在解析的連接類型不是直接的時候。 –

回答

3

下式成立:由當時的信號返回:

  1. 所有直接相連的槽已經被調用。

  2. 所有阻塞排隊的連接槽已被調用。

  3. 帶有排隊連接的插槽的所有目標對象都有相關的QMetaCallEvent發佈給他們。

因此,你有,如果你的其他代碼允許它你尋求充分的保證,如果連接是:

  • 直接,
  • 阻止排隊的,或
  • 自動與當前線程中的目標對象。

使用這些連接類型,在信號方法返回之前,所有插槽都被調用。回想一下,信號是其他普通的C++方法,其實現由moc生成。

還記得自動連接類型在信號發出時被解析。如果目標對象位於當前線程中,則使用直接連接,否則會產生排隊連接。

當然,所有這些保證都假定您的插槽沒有修改對象!不要忘記,僅僅通過const引用傳遞對象是不夠的 - 畢竟,一些對象可能能夠直接訪問對象。代碼的設計必須解決您尋求的保證。

你保證,如果連接是一定不能成立:

  • 排隊,或
  • 自動在比當前線程其他線程的目標對象。

通過參考將數據傳遞到直接連接的時隙不復制實例:

//main.cpp 
#include <QDebug> 

class Data { 
    int m_i; 
public: 
    Data(const Data & o) : m_i(o.m_i) { 
     qDebug() << "copy constructed"; 
    } 
    Data(int i = 0) : m_i(i) { 
     qDebug() << "constructed"; 
    } 
    Data(Data && o) : m_i(o.m_i) { 
     qDebug() << "move constructed"; 
    } 
    ~Data() { 
     qDebug() << "destructed"; 
    } 
    int i() const { return m_i; } 
}; 
Q_DECLARE_METATYPE(Data) 

QDebug operator<<(QDebug dbg, const Data & d) 
{ 
    dbg << "Data:" << d.i(); 
    return dbg; 
} 

class Object : public QObject { 
    Q_OBJECT 
public: 
    Q_SIGNAL void source(const Data &); 
    Q_SLOT void sink(const Data & d) { 
     qDebug() << "sinking" << d; 
    } 
}; 

int main() 
{ 
    qDebug() << QT_VERSION_STR; 
    Object o; 
    o.connect(&o, SIGNAL(source(Data)), SLOT(sink(Data))); 
    emit o.source(Data(2)); 
    return 0; 
} 

#include "main.moc" 

輸出:

4.8.6 
constructed 
sinking Data: 2 
destructed 

5.2.2 
constructed 
sinking Data: 2 
destructed 
+0

好吧,完美!所以當編譯時,'signal'只是被一長串函數調用所取代。 – user3050215

+0

@ user3050215信號不被任何東西代替,它是一個常規的C++方法調用。信號是一種常規方法,對於直接連接,本質上是迭代連接的函數指針列表並進行間接函數調用。當然,頂部櫻桃:) –