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

相关推荐
ambition2024243 分钟前
操作系统同步:读者-写者问题与读写公平法详解(附每个 PV 操作含义)
linux·开发语言·数据结构·unix
chuan.bai3 小时前
Java RAG 实战(第 11 篇):RAG 知识工作台网页
java·开发语言·人工智能
离陌在学C#6 小时前
C# 事件(Event)详解:从概念到实战
开发语言·c#
Terra.K6 小时前
Java异常学习[特殊字符]
java·开发语言·学习
葡萄城技术团队8 小时前
InfluxDB 2\.x 深度解析:核心架构、Flux 函数与制造业落地指南(三)
java·开发语言·架构
counting money8 小时前
Java IO流详解:从InputStream到文件操作实战
java·开发语言·python
wuyk5558 小时前
98.C语言易混难点:字符数组与字符串指针的底层差异
c语言·开发语言·c++·stm32·嵌入式硬件·算法
峥无8 小时前
从0到1手撕红黑树:封装实现 my_map 与 my_set(SGI-STL 源码级深度解析)
开发语言·c++·笔记·算法·stl
波特率1152008 小时前
C++新特性---属性说明符与标准属性
开发语言·c++
程序员小八7779 小时前
上海百度B端java后端日常实习一面
java·开发语言