Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to emit signal passing QObject pointer as parameter right before the passed object is going to be destroyed?

Lets consider this simple example:

Class Emitter: public QObject {
...
signal:
    surfaceDestroyed(QObject*);
public:
    void emittingMethod(QObject* surface) {
        emit surfaceDestroyed(surface);
        delete surface;
    }
}

I have a queued connection for this case

connect(emitterObject, SIGNAL(surfaceDestroyed(QObject*), receiverObject,
    SLOT(onSurfaceDestroyed(QObject*)), Qt::QueuedConnection);

In onSurfaceDestroyed method the received QObject is dereferenced and used

So the question is how safe this code is? I've read pretty much info on that on QT site and here, but I still don't have a clear understanding of the problem.

In my opinion this code is not safe, as a signal can be sent, then surface destroyed, than when an event comes for receiverObject once the event loop is processed and receiver object accesses released memory, thus SIGSEGV

This is a simplified example of real code, so it's hard to track if crashes can happen because of that.

like image 563
rightaway717 Avatar asked Dec 04 '13 13:12

rightaway717


1 Answers

It depends on the type of the signal-slot connection. Connections are direct by default if the sender and the receiver belong to the same thread. In this case the slot will be called immediately when you emit the signal. When the signal function is finished, you can be sure that the slot has also finished.

When the sender and the receiver belong to different threads, the connection is queued by default. In this case your code is not safe. The slot can be called much later than the signal was called. Even deleteLater will not save the situation because it's processed by the sender's thread's event loop and doesn't depend on the other thread's event loop.

So if you want to write such code, ensure that your objects are in the same thread. You can pass Qt::DirectConnection option to connect function to make connection type more clear.

If you want to use queued connection, you can emit e.g. aboutToBeDeleted signal in the sender. The receiver will receive that signal, process it somehow and respond with cleanUpCompleted signal that will trigger the actual object deletion.

Also consider using standard QObject::destroyed signal. It's called immediately before the object is destroyed but can be useful in many cases.

like image 197
Pavel Strakhov Avatar answered Oct 09 '22 15:10

Pavel Strakhov