让我们考虑这个简单的例子:
Class Emitter: public QObject {
...
signal:
surfaceDestroyed(QObject*);
public:
void emittingMethod(QObject* surface) {
emit surfaceDestroyed(surface);
delete surface;
}
}
我有这种情况的排队连接
connect(emitterObject, SIGNAL(surfaceDestroyed(QObject*), receiverObject,
SLOT(onSurfaceDestroyed(QObject*)), Qt::QueuedConnection);
在onSurfaceDestroyed方法中,接收到的QObject被解除引用并使用
所以问题是这段代码有多安全?我在QT网站和这里已经阅读了很多相关信息,但我仍然没有清楚地了解这个问题。
在我看来这个代码是不安全的,因为一旦处理了事件循环并且接收者对象访问释放的内存,就会发送信号然后表面被破坏,而不是事件发生时,因此SIGSEGV
这是真实代码的简化示例,因此很难跟踪崩溃是否会因此而发生。
答案 0 :(得分:7)
这取决于信号插槽连接的类型。如果发送方和接收方属于同一个线程,则默认情况下连接是 direct 。在这种情况下,当您发出信号时,将立即调用插槽。信号功能完成后,您可以确定插槽已完成。
当发件人和收件人属于不同的线程时,默认情况下连接排队。在这种情况下,您的代码不安全。可以在调用信号之前调用插槽。即使deleteLater
也不会保存这种情况,因为它由发送者的线程的事件循环处理,并且不依赖于其他线程的事件循环。
因此,如果您想编写此类代码,请确保您的对象位于同一个线程中。您可以将Qt::DirectConnection
选项传递给connect
函数,以使连接类型更加清晰。
如果您想使用排队连接,可以发出例如发件人中发出aboutToBeDeleted
信号。接收器将接收该信号,以某种方式处理它并以cleanUpCompleted
信号响应,这将触发实际的对象删除。
还要考虑使用标准QObject::destroyed
信号。它在对象被销毁之前立即调用,但在许多情况下可能很有用。