0

I have problem. I have a custom class BasicSpace. This class isntt qobject (don't have macro) and don't inherit by qobject. It is simple class with some data, qtime etc. I have:

connect(connector,SIGNAL(finishedReadData(QVector<BasicSpace>&)),&window,SLOT(updateData(QVector<BasicSpace>&)));

I try

qRegisterMetaType< QVector<BasicSpace> >("QVector<BasicSpace>");

in main.cpp.

But Qt still when slot is called take me msg:

QObject::connect: Cannot queue arguments of type 'QVector&' (Make sure 'QVector&' is registered using qRegisterMetaType().)

My concentration is betwen thread.

My project is advanced, so I try avoid typedef solutions with different name, so I don't test it. Someone can help me?

EDIT THX Frank. I replace reference to value like QVector, without &. This work but i have doubt. It works but thread connections always copy data, so prabodly without reference data is doubled copy, first time in function and second time betwen thread?

I rhing that is 50% solved. I have working code but main problem - reference value with template type in queued connection is unsolved.

Kirk Brodie
  • 42
  • 1
  • 7
  • Don’t pass non-const reference, but either by const reference or by value. I.e. `finishedReadData(QVector)`. – Frank Osterfeld Dec 03 '15 at 19:26
  • Frank is right. Nevertheless it works for my without problems like you try it. Without any need to register something. Could you please post your slot and signal declarations. Usually one doesn't need to think much about the signal & slot parameters and doesn't need to register that type for most cases. – Aaron Dec 03 '15 at 19:42

1 Answers1

0

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:

  1. myObjectSignal1 signal is connected to myObjectSlot using Qt::DirectConnection.

  2. MyObject is created inside Widget::testDirectConnection.

  3. myObjectSignal1 signal triggers myObjectSlot as a normal function call.

  4. MyObject is passed by reference into myObjectSlot.
  5. myObjectSlot execution finishes.
  6. MyObject is destroyed as control leaves Widget::testDirectConnection.

The output will be:

MyObject::MyObject() 
MyObject::~MyObject() 

The Qt::QueuedConnection scenario:

  1. myObjectSignal2 signal is connected to myObjectSlot using Qt::QueuedConnection.
  2. MyObject is created inside Widget::testQueuedConnection.

  3. myObjectSignal2 signal triggers and MyObject is copied into the event queue.

  4. MyObject is destroyed as the control leaves Widget::testQueuedConnection.
  5. Control returns to the event loop and execute myObjectSlot which gets a copy of MyObject.
  6. 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/

hank
  • 9,553
  • 3
  • 35
  • 50