简体   繁体   中英

Qt, data integrity when sending a reference as a signal

If I send a signal with a reference to an object, do I have any sort of guarantee that the slots will handle the signal before the object is subjected to changes by other parts of the program?

Or do I have to send a deep copy of the object with the signal to be sure?

The following holds: By the time the signal returns:

  1. All directly connected slots have been invoked.

  2. All blocking-queued connected slots have been invoked.

  3. All of the target objects with queued-connected slots have the relevant QMetaCallEvent posted to them.

Thus, you have the full guarantee you seek if your other code allows it, and if the connection is:

  • direct,
  • blocking-queued, or
  • automatic with the target object in the current thread.

With those connection types, the slots are all invoked before the the signal method returns. Recall that signals are otherwise ordinary C++ methods with their implementation generated by moc.

Also recall that the automatic connection types are resolved at the time the signal is emitted . If the target object is in the current thread, a direct connection is used, otherwise a queued connection results.

Of course, all those guarantees assume that none of your slots modify the object! Don't forget that merely passing the object by const reference is not enough - after all, some objects may be able to access your object directly. The design of your code must address the guarantees that you seek.

Your guarantee necessarily can't hold if the connection is:

  • queued, or
  • automatic with the target object in thread other than the current thread.

Passing data by reference to directly connected slots does not copy the instances:

//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"

Output:

4.8.6 
constructed 
sinking Data: 2 
destructed 

5.2.2 
constructed 
sinking Data: 2 
destructed 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM