When you connect a signal and a slot of objects that live in the same thread, the Qt::DirectConnection
type is used. In this case the slot is executed as a normal function call. You don't have to register your data type via qRegisterMetaType
, and when you send your data as a reference it is not copied.
When sender and receiver objects do not live in the same thread, the Qt::QueuedConnection
type is used. Now, when you send some data, it is copied into the event queue, no matter if you send it by value or by reference. Also your data type must be registered using qRegisterMetaType
.
Here is a simple example that illustrates this behaviour:
class MyObject
{
public:
MyObject()
{
qDebug() << Q_FUNC_INFO;
}
MyObject(const MyObject &other)
{
qDebug() << Q_FUNC_INFO;
}
~MyObject()
{
qDebug() << Q_FUNC_INFO;
}
};
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
signals:
void myObjectSignal1(const MyObject &obj);
void myObjectSignal2(const MyObject &obj);
public slots:
void testDirectConnection();
void testQueuedConnection();
void myObjectSlot(const MyObject &obj);
};
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QHBoxLayout *layout = new QHBoxLayout(this);
QPushButton *b1 = new QPushButton;
b1->setText("direct");
layout->addWidget(b1);
connect(b1, SIGNAL(clicked()), this, SLOT(testDirectConnection()));
QPushButton *b2 = new QPushButton;
b2->setText("queued");
layout->addWidget(b2);
connect(b2, SIGNAL(clicked()), this, SLOT(testQueuedConnection()));
qRegisterMetaType<MyObject>("MyObject");
connect(this, SIGNAL(myObjectSignal1(MyObject)),
this, SLOT(myObjectSlot(MyObject)));
connect(this, SIGNAL(myObjectSignal2(MyObject)),
this, SLOT(myObjectSlot(MyObject)), Qt::QueuedConnection);
}
Widget::~Widget()
{
}
void Widget::testDirectConnection()
{
MyObject obj;
emit myObjectSignal1(obj);
}
void Widget::testQueuedConnection()
{
MyObject obj;
emit myObjectSignal2(obj);
}
void Widget::myObjectSlot(const MyObject &obj)
{
}
The Qt::DirectConnection
scenario:
myObjectSignal1
signal is connected to myObjectSlot
using
Qt::DirectConnection
.
MyObject
is created inside Widget::testDirectConnection
.
myObjectSignal1
signal triggers myObjectSlot
as a normal function call.
MyObject
is passed by reference into myObjectSlot
.
myObjectSlot
execution finishes.
MyObject
is destroyed as control leaves Widget::testDirectConnection
.
The output will be:
MyObject::MyObject()
MyObject::~MyObject()
The Qt::QueuedConnection
scenario:
myObjectSignal2
signal is connected to myObjectSlot
using
Qt::QueuedConnection
.
MyObject
is created inside Widget::testQueuedConnection
.
myObjectSignal2
signal triggers and MyObject
is copied into the event queue.
MyObject
is destroyed as the control leaves Widget::testQueuedConnection
.
- Control returns to the event loop and execute
myObjectSlot
which gets a copy of MyObject
.
- The copy of
MyObject
is destroyed as control leaves myObjectSlot
.
The output will be:
MyObject::MyObject() // object is created inside testQueuedConnection
MyObject::MyObject(const MyObject&) // object is copied
MyObject::~MyObject() // object is destroyed
MyObject::~MyObject() // copy is destroyed
If you want to avoid additional object copy, you can allocate memory for you data on the heap using new
operator and then pass a pointer. But in this case you must make sure that your object is destroyed when processing is over.
A good article on arguments copying in Qt signal-slot connections: http://www.embeddeduse.com/2013/06/29/copied-or-not-copied-arguments-signals-slots/