我想知道emit
。它会重复数据吗?
如果我必须通过它传递一个 1MB 字节数组,那么内存中将存在多少个该字节数组的副本?
这取决于您的信号如何连接到插槽。
如果您使用默认连接,Qt::DirectConnection
并且两个QObject
s 在同一个线程中,则根据您定义参数的方式(按引用传递或按传递),参数将被视为以通常方式调用函数-价值)。
如果您使用连接Qt::QueuedConnection
或在线程之间连接,则参数参数将被复制并移交给特殊的QEvent
并添加到接收线程的事件队列中。然后,当它有机会时,这将由接收线程处理。
这取决于如何建立连接以及如何传递参数。
按值传递(即signals: void foo(Bar);
)
Bar
到被调用者)。moc
(一个副本,与上面的相同),“打包”参数并调用QMetaObject::activate
最终调用您的类的qt_static_metacall
调用插槽 (作为正常的函数调用),产生第二个副本。qt_static_metacall
槽的调用相同。通过 const 引用传递(即signals: void foo(Bar const&);
)
通过(非常量)引用(即signals: void foo(Bar&);
)
文档中提到了复制到事件中:
对于排队连接,参数必须是 Qt 元对象系统已知的类型,因为Qt 需要复制参数以将它们存储在幕后的事件中。
现在真正的问题是:这重要吗?
如果您使用的是使用隐式共享的 Qt 容器类,则在通常情况下并不重要 - 除非需要,否则不会复制有效负载。因此,副本通常不会对整体性能产生重大影响。
如果您不使用隐式共享,那么按值传递大量对象可能不是正确的选择,但插槽调用会比普通函数调用更昂贵。直接连接的槽和 pass-by-const-ref 的行为与普通函数调用相同,但排队的槽会更昂贵。
All Qt containers implement "copy on write" pattern. So when you are passing container by value nothing is copied until you will use none-const method of this container.
So bottom line is: it is safe (it will not double memory consumption) to pass large qt containers through signals and slots.