让我们考虑这个简单的例子:
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
这是真实代码的简化示例,因此很难跟踪是否会因此发生崩溃。
最佳答案
这取决于信号槽连接的类型。如果发送方和接收方属于同一个线程,则连接默认为直接。在这种情况下,插槽将在您发出信号时立即被调用。当信号函数完成时,您可以确定插槽也已完成。
当发送方和接收方属于不同的线程时,连接默认排队。在这种情况下,您的代码不安全。调用槽的时间可以比调用信号晚得多。即使是 deleteLater
也不会挽救这种情况,因为它是由发送方线程的事件循环处理的,不依赖于其他线程的事件循环。
所以如果你想写这样的代码,确保你的对象在同一个线程中。您可以将 Qt::DirectConnection
选项传递给 connect
函数以使连接类型更加清晰。
如果你想使用排队连接,你可以发出例如发件人中的 aboutToBeDeleted
信号。接收器将接收到该信号,以某种方式对其进行处理,并以触发实际对象删除的 cleanUpCompleted
信号进行响应。
同时考虑使用标准的 QObject::destroyed
信号。它在对象被销毁之前立即调用,但在许多情况下很有用。
关于c++ - 在传递的对象将要被销毁之前,发出传递 QObject 指针作为参数的信号是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20376571/