I am prity new on Qt an got some issues with QSharedPointer passing around within signals. I am working with two threads (UI and a worker). The worker sends signals to the UI using signals that contain QSharedPointer of a custom QObject:
class MyObject : QObject {...}
class Window : public QWidget {
Q_OBJECT
public slots:
void onFound(QSharedPointer<MyObject>);
}
class Worker : public QObject {
Q_OBJECT
public signals:
void found(QSharedPointer<MyObject>);
}
I connect the workers found with the windows onFound with Qt::QueuedConnection because they live in different Threads and the communication therefore has to be asynchronous.
Now I observe the folowing behavior, when I pass a the last QSharedPointer refering to my object:
- The signal moc casts the reference to my pointer to
void*and arcives it. - The function returns resulting in the shared pointer and the corresponding object to be destroyed.
That's not what I expected - though it's reasonable. Are QSharedPointer in general designed to be passed through signals that way? And if so, is there a mecanism to keep a reference while it is queued?
I considered the folowing solutions, but I'm not totally fine with neither of them:
- Keep a reference somewhere that keeps reference while it is queued. But where is a reasonable place to do that and when should I let it go.
- Make the connection
Qt::DirectConnectionbut then I am still have to switch the thread somehow (same situation as before) - Introduce a new signal/slot with
std::functionparameter for passing a lambda function to be executed in the target thread and capturing a copy of my shared pointer. (This is my current solution but it's not perty elegant, isn't it?)
Do you have any other suggestions or ideas?
The signal return does not destroy the corresponding object. The
QMetaObject::activatecall copies the shared pointer. Here's the implementation ofsendsignal:You're probably experiencing a race: by the time the thread where the signal was emitted resumes execution, the destination thread has already received the object. Thus it appears in the emitting thread that the object is gone - because, by that time, it is. Yet the target object receives the instance just fine. It works fine.
The example below illustrates that it works in both single- and multi-threaded cases, and then reproduces your problem by ensuring that the race is always won by the destination thread: