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复制。

相关推荐
z落落3 小时前
C# WinForm Socket 转串口设备服务器+Modbus CRC16校验+Socket 客户端
服务器·开发语言·c#
小灰灰搞电子8 小时前
Rust+Slint 实现动态消息提示框源码分享
开发语言·后端·rust
传奇开心果编程10 小时前
【Rust入门知识点学与练】第21课:Trait 进阶 Advanced Traits
开发语言·学习·rust
新时代牛马10 小时前
字符设备驱动完整篇:从 cdev_add、file_operations 到chrdev_open 与排障
开发语言·python
swordbob10 小时前
ReentrantLock 与 AQS 完整学习手册
java·开发语言
白山编程大哥11 小时前
Java OutputStreamWriter 详解:从字符到字节的桥梁
java·开发语言·python
shmily麻瓜小菜鸡12 小时前
JavaScript / TypeScript 易踩坑知识点 —— 异步编程类
开发语言·javascript·typescript
七夜zippoe12 小时前
为什么 2026 年每个 Java 团队都该懂 AI Agent
java·开发语言·人工智能
znnnk12 小时前
【Python】GUI 开发从入门到实战(三):PyQt/PySide 进阶之路
开发语言·python·pyqt
Despacito100613 小时前
Java后端性能探查工具速查表
java·开发语言