我想知道emit
。它是否重复数据?
如果我必须传递一个1MB字节的数组,那么该字节数组的副本将在内存中存在多少?
答案 0 :(得分:5)
这取决于您的信号如何连接到插槽。
如果您使用默认连接Qt::DirectConnection
,并且两个QObject
在同一个线程中,那么参数将被视为您按照常规方式调用函数定义参数(按引用传递或按值传递)。
如果使用Qt::QueuedConnection
进行连接或者在线程之间连接,则会复制参数参数并将其移交给特殊的QEvent
并添加到接收线程的事件队列中。然后,当接收线程有机会时,它将由接收线程处理。
答案 1 :(得分:3)
这取决于连接的方式以及传递参数的方式。
按值传递(即signals: void foo(Bar);
)
Bar
从调用者复制到被调用者)。moc
生成的emit函数被调用(一个副本,与上面的一个相同)," packages"参数和调用QMetaObject::activate
最终调用您的类qt_static_metacall
,它调用插槽(作为普通函数调用),产生第二个副本。qt_static_metacall
调用。通过const引用(即signals: void foo(Bar const&);
)
通过(非常)引用(即signals: void foo(Bar&);
)
the docs中提到了事件的副本:
对于排队连接,参数必须是Qt的元对象系统已知的类型,因为 Qt需要复制参数以在事件中存储它们
现在真正的问题是:这有关系吗?
如果您正在使用使用implicit sharing的Qt容器类,那么在通常情况下它确实无关紧要 - 除非需要,否则无法复制有效负载。因此,副本一般不会对整体表现产生重大影响。
如果你不使用隐式共享,那么按值传递大量对象可能不是首选的正确选择,但是槽调用比普通函数调用更昂贵。直接连接的插槽和pass-by-const-ref的行为与普通的函数调用相同,但排队的插槽将更加昂贵。
答案 2 :(得分:0)
所有Qt容器都实现“copy on write”模式。因此,当您按值传递容器时,不会复制任何内容,直到您将使用此容器的非const方法。
所以底线是:通过信号和插槽传递大型qt容器是安全的(不会使内存消耗量增加一倍)。