Qt信号槽在异步连接时需要将参数进行复制吗?

cpp 复制代码
class Sender : public QObject
{
	Q_OBJECT
signals:
	// void testSignal(QString msg);        // #1
	// void testSignal(const QString& msg); // #2
};

如上所示,当testSignal连接的槽函数在另一个线程时,有必要将参数类型写为#1这样吗?

我们可以在moc文件中看到信号的实现:

cpp 复制代码
void Sender::testSignal(const QString & _t1)
{
    QMetaObject::activate<void>(this, &staticMetaObject, 1, nullptr, _t1);
}

而QMetaObject::activate的实现参考Qt6.11源代码可见:

cpp 复制代码
void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
                           void **argv)
{
    int signal_index = local_signal_index + QMetaObjectPrivate::signalOffset(m);

    if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
        doActivate<true>(sender, signal_index, argv);
    else
        doActivate<false>(sender, signal_index, argv);
}

template <bool callbacks_enabled>
void doActivate(QObject *sender, int signal_index, void **argv)
{
	...
    // determine if this connection should be sent immediately or
    // put into the event queue
    if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
        || (c->connectionType == Qt::QueuedConnection)) {
        queued_activate(sender, signal_index, c, argv);
            continue;
	...
}

static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv)
{
...
    auto ev = c->isSlotObject ?
        std::make_unique<QQueuedMetaCallEvent>(c->slotObj,
                                               sender, signal, nargs, argTypes.data(), argv) :
        std::make_unique<QQueuedMetaCallEvent>(c->method_offset, c->method_relative, c->callFunction,
                                               sender, signal, nargs, argTypes.data(), argv);
...
}

可见异步信号槽将信号包装成了QQueuedMetaCallEvent,而QQueuedMetaCallEvent的构造函数如下:

cpp 复制代码
QQueuedMetaCallEvent::QQueuedMetaCallEvent(ushort method_offset, ushort method_relative,
                                           QObjectPrivate::StaticMetaCallFunction callFunction,
                                           const QObject *sender, int signalId, int argCount,
                                           const QtPrivate::QMetaTypeInterface * const *argTypes,
                                           const void * const *argValues)
    : QMetaCallEvent(sender, signalId, {nullptr, nullptr, callFunction, argCount,
                     method_offset, method_relative}),
      prealloc_()
{
    copyArgValues(argCount, argTypes, argValues);
}

inline void QQueuedMetaCallEvent::copyArgValues(int argCount, const QtPrivate::QMetaTypeInterface * const *argTypes,
                                                const void * const *argValues)
{
    allocArgs();
    void **args = d.args_;
    QMetaType *types = reinterpret_cast<QMetaType *>(d.args_ + d.nargs_);
    int inplaceIndex = 0;

    if (argCount) {
        types[0] = QMetaType(); // return type
        args[0] = nullptr; // return value pointer
    }
    // no return value

    for (int n = 1; n < argCount; ++n) {
        types[n] = QMetaType(argTypes[n]);
        if (typeFitsInPlace(types[n]) && inplaceIndex < InplaceValuesCapacity) {
            // Copy-construct in place
            void *where = &valuesPrealloc_[inplaceIndex++].storage;
            types[n].construct(where, argValues[n]);
            args[n] = where;
        } else {
            // Allocate and copy-construct
            args[n] = types[n].create(argValues[n]);
        }
    }
}

可见QQueuedMetaCallEvent将参数复制了一份,所以信号参数使用QString而不使用const QString&是没有必要的,反而增加了开销,而QQueuedMetaCallEvent已经将参数复制了一份,由事件循环系统将QQueuedMetaCallEvent派发到槽函数所在的线程后,也就相当于槽函数所在线程的本线程调用,槽函数参数也应当使用const QString& 而不是使用QString复制。

相关推荐
茉莉玫瑰花茶1 分钟前
GO [ 内存与变量逃逸分析 ]
开发语言·后端·golang
lhh_qrsly23 分钟前
OTA 加密完整方案(嵌入式 IoT 常用)
开发语言·物联网·php
Nontee30 分钟前
Quartz 新手入门:定时任务的两个承诺
开发语言·windows·python
\光辉岁月/1 小时前
2.异常类
java·开发语言·异常类
淡海水1 小时前
05-03-源码-Boehm GC分配与碎片管理
开发语言·算法·unity·c#·游戏引擎·gc
努力实干1 小时前
C++ 面向对象与工程架构
开发语言·c++·架构
代钦塔拉1 小时前
【C++/Qt 进阶】设计模式系列(6):桥接模式——把“两个独立变化的维度“拆开
c++·qt·设计模式
十年Java程序媛1 小时前
JVM 基础与 GC 垃圾回收详解|可达性分析、分代模型、垃圾收集器、STW
java·开发语言·jvm·spring boot·后端·面试
估值探索者1 小时前
【Python量化选股流水线 #03】候选股怎么排序?动量+低波+流动性三因子打分取 Top-N
开发语言·python·接口·api接口·股票数据接口·数据接口·股票数据api接口
骑士雄师1 小时前
supervisor 中关于上下文多轮信息维护常用到的python语法
开发语言·python