c++ - 在传递的对象将要被销毁之前,发出传递 QObject 指针作为参数的信号是否安全?

标签 c++ qt signals-slots

让我们考虑这个简单的例子:

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/

相关文章:

c++ - 跨成员共享对象

c++ - 尝试连接到 tcp 套接字时连接被拒绝 (linux)

qt - QGLWidget - 发生失真

c++ - 关于如何使用 cpp-netlib 进行异步 http get 请求的示例

c++ - Qt::WA_DeleteOnClose

c++ - QT 在单独的线程中管理 OpenGL 上下文

python - PyQT 与 PyObjc/Cocoa-Python 对比

c++ - 如何在 QML 中创建 Q_GADGET 结构的新实例?

Qt: SIGNAL, SLOT 宏声明

c++ - 您能否/如何重新分配使用 placement new 创建的 C++ 对象?