为什么不建议在Qt中通过信号发出大量数据?
没有这样的建议.请参阅此问题以供讨论.
首先,当我们通过信号参数传递数据时,我们通过值或引用传递对象实例.
然而,必须区分数据和对象.A QString可能包含大量数据,但并不意味着它会在复制字符串对象时复制数据.
// one million worth of 'a's, about 2 megabytes worth of data
const QString large1(1000*1000, QLatin1Char('a'));
Run Code Online (Sandbox Code Playgroud)
large1是一种QString类型的对象.碰巧的是,QString实现使用隐式数据共享和复制对象 不复制的数据.因此,复制字符串很便宜,尽管它比复制指针值更昂贵.
现在让我们考虑另一种字符串类型:
// one million worth of 'a's
const std::string large2(1000*1000, 'a');
Run Code Online (Sandbox Code Playgroud)
large2是一种std::string类型的对象.大多数的实现不使用隐式数据共享,并复制对象 将复制的数据.
信号槽系统中有三种情况会强制复制一个对象:
在信号发射时,当信号的参数类型是值类型时.例如:
Q_SIGNAL void mySignal(std::string); // copies or moves the object and data
Q_SIGNAL void mySignal(const std::string &); // no copies here
Q_SIGNAL void mySignal(QString); // copies or moves the object, but not the data
Q_SIGNAL void mySignal(const QString &); // no copies here
Run Code Online (Sandbox Code Playgroud)在调用插槽时,插槽的参数类型是值类型.实例与上述相同.
每次使用排队连接来调用插槽.
当您选择排队的连接类型,或者连接是自动的(默认情况下),并且接收器对象在发出信号时存在于另一个线程中时,会发生这种情况.
假设我们有以下课程:
class C : public QObject {
public:
Q_SIGNAL void signal1(const QString &); // correct
Q_SIGNAL void signal2(QString); // don't do that
Q_SIGNAL void signal3(const std::string &); // correct
Q_SIGNAL void signal4(std::string); // really don't do that
Q_SLOT void slot1(const QString &); // correct
Q_SLOT void slot2(QString); // only do that if you need a value to modify
Q_SLOT void slot3(const std::string &); // correct
Q_SLOT void slot4(std::string); // only do that if you need a value to modify
};
Run Code Online (Sandbox Code Playgroud)
我们现在可以尝试多种信号和插槽组合.假设在每种情况下信号都发出N一次,并且它连接到M插槽:
对象副本数,直接连接数
signal1 signal2 signal3 signal4
slot1 0 N - -
slot2 N*M N*(M+1) - -
slot3 - - 0 N
slot4 - - N*M N*(M+1)
Run Code Online (Sandbox Code Playgroud)
数据副本数,直接连接
signal1 signal2 signal3 signal4
slot1 0 0 - -
slot2 0 0 - -
slot3 - - 0 N
slot4 - - N*M N*(M+1)
Run Code Online (Sandbox Code Playgroud)
对象,排队连接的副本数
signal1 signal2 signal3 signal4
slot1 N*M N*(M+1) - -
slot2 2*N*M 2*N*(M+1) - -
slot3 - - N*M N*(M+1)
slot4 - - 2*N*M 2*N*(M+1)
Run Code Online (Sandbox Code Playgroud)
数据副本数,排队连接数
signal1 signal2 signal3 signal4
slot1 0 0 - -
slot2 0 0 - -
slot3 - - N*M N*(M+1)
slot4 - - 2*N*M 2*N*(M+1)
Run Code Online (Sandbox Code Playgroud)
有关测试用例,请参阅此答案.