Search code examples
c++qtcopy-constructorqt-signals

How to make Qt Signal emit by value without compile errors instead of reference?


I read that the signal/slot concept in qt should always pass arguments by value instead of reference to ensure that signals/slots work flawlessly between threads.

I now have a piece of code that will only compile when the argument to a signal is emitted by reference, not value:

#include <QObject>

class mythirdclass {
public:
    mythirdclass();
};

class mysecondclass : public QObject, public mythirdclass {
public:
    mysecondclass(mythirdclass third);
};

class myclass : public QObject {
    Q_OBJECT
public:
    myclass();

signals:
    // not working
    void messageReceived(mysecondclass mymessage);
    // working
    // void messageReceived(mysecondclass &mymessage);
};

myclass::myclass()
{
    mythirdclass third;
    mysecondclass msg(third);
    emit messageReceived(msg);

}

mysecondclass::mysecondclass(mythirdclass third)
{
    // DO stuff
}

mythirdclass::mythirdclass()
{
}

The compiler error is:

..\example\main.cpp: In constructor 'myclass::myclass()':
..\example\main.cpp:28:20: error: use of deleted function 'mysecondclass::mysecondclass(const mysecondclass&)'
  emit signal(second);
                    ^
..\example\main.cpp:8:7: note: 'mysecondclass::mysecondclass(const mysecondclass&)' is implicitly deleted because the default definition would be ill-formed:
 class mysecondclass : QObject, public mythirdclass {
       ^

Based on the errors I thought abour writing a copy constructor for mysecondclass, however after some attempts I gave up for now, because I didn't get it right.

So my questions are:

  • why is the compiling failing in the first place?
  • if it fails because of a missing copy constructor, why is the compiler not able to define one implicitly?
  • how would the working copy constructor in my case look like?

Thanks in advance.


Solution

  • Why is the compiling failing in the first place?

    Because passing by value implies copying, and if the copy-constructor is deleted, then it simply can't pass by value and your function cannot be compiled with this signature, while it can receive its argument by reference because it doesn't involve copying.

    If it fails because of a missing copy constructor, why is the compiler not able to define one implicitly?

    It actually fails because it hasn't been able to define one implicitly. The reason for that is that your class derives from QObject. And that QObject doesn't have a public or protected copy-constructor, by design. So the compiler cannot define one implicitly.

    How would the working copy constructor in my case look like?

    Given the nature of QObjects, and the design decision that's behind it when it comes to QObjects not being copyable, I would recommend against using signals and slots that take QObjects or class deriving from it by value (or simply any function that does this, and signals/slots are mainly functions deep down), but instead by reference or by pointer.