Qt信号槽传const&和传值有什么不同

之前一直在纠结Qt的信号槽是否要传引用,如果传引用会不会有悬挂引用的问题。

故参考Copied or Not Copied: Arguments in Signal-Slot Connections?这篇博客测试一下

CopyTest.h

#include 

class CCopyable
{
public:
    // qRegisterMetaType的类需要默认构造函数
    CCopyable();
    CCopyable(int id, const QString &name);
    CCopyable(const CCopyable &rhs);
    ~CCopyable();
    CCopyable &operator=(const CCopyable &rhs);

private:
    int m_id;
    QString m_name;
};

class CSender : public QObject
{
    Q_OBJECT
public:
    CSender(QObject *parent = nullptr);
    ~CSender() {}

    void sendSignal();

signals:
    void sendConstRef(const CCopyable &c);
    void sendValue(CCopyable c);

    void testSig(QString);
    void testSig(QString, int);
    //void testSig(const QString&);
};

class CReceiver : public QObject
{
    Q_OBJECT
public:
    CReceiver(QObject *parent = nullptr);
    ~CReceiver() {}

public slots:
    void receiveConstRef(const CCopyable &c);
    void receiveValue(CCopyable c);
};


void signalSlotCopyTest();

CopyTest.cpp

#include "CopyTest.h"
#include 
#include 
#include 


#define CaseNum   4
#define EnableQueuedConnection 

CCopyable::CCopyable()
{
}

CCopyable::CCopyable(int id, const QString &name)
    : m_id(id)
    , m_name(name)
{
}

CCopyable::~CCopyable()
{
}

CCopyable::CCopyable(const CCopyable &rhs)
{
    qDebug() << "copy construct";
    m_id = rhs.m_id;
    m_name = rhs.m_name;
}

CCopyable& CCopyable::operator=(const CCopyable &rhs)
{
    qDebug() << "assign";
    if (this == &rhs)
    {
        return *this;
    }
    m_id = rhs.m_id;
    m_name = rhs.m_name;
    return *this;
}

CSender::CSender(QObject *parent)
    : QObject(parent)
{
}

CReceiver::CReceiver(QObject * parent)
    : QObject(parent)
{
    QThread *t = new QThread;
    moveToThread(t);
    t->start();
}

void CReceiver::receiveConstRef(const CCopyable &c)
{
    qDebug() << "receiveConstRef";
}

void CReceiver::receiveValue(CCopyable c)
{
    qDebug() << "receiveValue";
}

void signalSlotCopyTest()
{
    CSender *sender = new CSender;
    CReceiver* receiver = new CReceiver;

#ifdef EnableQueuedConnection
    qRegisterMetaType("CCopyable");
    Qt::ConnectionType ctype = Qt::QueuedConnection;
#else
    Qt::ConnectionType ctype = Qt::DirectConnection;
#endif // EnableQueuedConnection

    switch (CaseNum)
    {
    case 1:
        QObject::connect(sender, &CSender::sendConstRef, receiver, &CReceiver::receiveConstRef, ctype);
        break;
    case 2:
        QObject::connect(sender, &CSender::sendValue, receiver, &CReceiver::receiveConstRef, ctype);
        break;
    case 3:
        QObject::connect(sender, &CSender::sendConstRef, receiver, &CReceiver::receiveValue, ctype);
        break;
    case 4:
        QObject::connect(sender, &CSender::sendValue, receiver, &CReceiver::receiveValue, ctype);
        break;
    default:
        break;
    }

    QTimer::singleShot(1000, [sender]() {
        sender->sendSignal();
    });
}

void CSender::sendSignal()
{
    CCopyable copyable(1,"momo");

    switch (CaseNum)
    {
    case 1:
        emit sendConstRef(copyable);
        break;
    case 2:
        emit sendValue(copyable);
        break;
    case 3:
        emit sendConstRef(copyable);
        break;
    case 4:
        emit sendValue(copyable);
        break;
    default:
        break;
    }
}

Qt信号槽传const&和传值有什么不同_第1张图片

测试结果跟参考博客一样:

如果信号和槽参数都传值的话,会多调用两次拷贝构造函数。而如果信号槽连接方式是Qt::QueuedConnection的话,又会多调用一次拷贝构造函数。

所以结论就是:

  1. Qt为了避免队列连接造成的悬挂引用问题,会拷贝一次参数。跨线程调用槽(且是Qt::QueuedConnection)的话这一次拷贝无法避免
  2. 能传引用就传引用,避免参数多两次拷贝

你可能感兴趣的:(Qt,Qt信号槽是否要传引用,qt)