Disconnect all incoming and outgoing connections from QObject-derived class manually
-
I am trying to solve a crash caused by a slot called during destruction of my class. The problem is, that my own destructor has already run, but QObject's destructor has not yet run, so connections are still active.
Since I don't just want to solve this one case, but prevent future cases like this, I'd like to move the disconnection of signals and slots to an earlier time, into a destructor of a custom base class of mine. That way, the offending slot would never be called.
However, I have found no way according to docs to disconnect everything from an object both incoming and outgoing. No list of active connection in QObject or QMetaObject, either. The destructor in QObject does lots of internal stuff, but clearly doesn't use the public-interface disconnect (or similar) methods.
Any ideas how I can safely disconnect everything to AND from and object?
-
If documentation is right, it should be enough to call:
disconnect();
or:
QObject::disconnect(this, nullptr, nullptr, nullptr);
See the docs
-
@sierdzio
I think the OP is (also) asking to disconnect everywhere one of his objects is a slot to any signal. I think your second one does it where it's the signaller? Don't know about the first? Does either of these do it? -
If documentation is right, it should be enough to call:
disconnect();
or:
QObject::disconnect(this, nullptr, nullptr, nullptr);
See the docs
@sierdzio said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
If documentation is right, it should be enough to call:
disconnect();
or:
QObject::disconnect(this, nullptr, nullptr, nullptr);
See the docs
The way I read the docs, this will only disconnect all signals of the object, but it will not disconnect slots connected to other object's signals
-
@JonB
The first one is equivalent to the second.
So both of them cannot disconnect the object's slots from "any object's signal", which is impossible.The sender may never be 0. (You cannot disconnect signals from more than one object in a single call.)
@Bonnie said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
@JonB
The first one is equivalent to the second.
So both of them cannot disconnect the object's slots from "any object's signal", which is impossible.The sender may never be 0. (You cannot disconnect signals from more than one object in a single call.)
Impossible is a strong word, given that QObject's destructor seems to manage that
-
@Bonnie said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
@JonB
The first one is equivalent to the second.
So both of them cannot disconnect the object's slots from "any object's signal", which is impossible.The sender may never be 0. (You cannot disconnect signals from more than one object in a single call.)
Impossible is a strong word, given that QObject's destructor seems to manage that
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
Impossible is a strong word, given that QObject's destructor seems to manage that
Fine, impossible by calling disconnect
-
I am trying to solve a crash caused by a slot called during destruction of my class. The problem is, that my own destructor has already run, but QObject's destructor has not yet run, so connections are still active.
Since I don't just want to solve this one case, but prevent future cases like this, I'd like to move the disconnection of signals and slots to an earlier time, into a destructor of a custom base class of mine. That way, the offending slot would never be called.
However, I have found no way according to docs to disconnect everything from an object both incoming and outgoing. No list of active connection in QObject or QMetaObject, either. The destructor in QObject does lots of internal stuff, but clearly doesn't use the public-interface disconnect (or similar) methods.
Any ideas how I can safely disconnect everything to AND from and object?
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
I am trying to solve a crash caused by a slot called during destruction of my class. The problem is, that my own destructor has already run, but QObject's destructor has not yet run, so connections are still active.
IMHO, you have a threading issue here.
For me, to call a slots during destructor, the call have to be started from another thread and the connection type isQt::DirectConnection
.Perhaps you have to look at this?
-
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
I am trying to solve a crash caused by a slot called during destruction of my class. The problem is, that my own destructor has already run, but QObject's destructor has not yet run, so connections are still active.
IMHO, you have a threading issue here.
For me, to call a slots during destructor, the call have to be started from another thread and the connection type isQt::DirectConnection
.Perhaps you have to look at this?
@KroMignon said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
I am trying to solve a crash caused by a slot called during destruction of my class. The problem is, that my own destructor has already run, but QObject's destructor has not yet run, so connections are still active.
IMHO, you have a threading issue here.
For me, to call a slots during destructor, the call have to be started from another thread and the connection type isQt::DirectConnection
.Perhaps you have to look at this?
No, it's quite clearly not a threading issue. Simply put, I have a custom editable text item derived from QGraphicsObject in a Graphics View hierarchy. If the item is destroyed, it notifies that editing was canceled through a signal.
Now I connected this signal to a slot of the text editor's parent item. The QGraphicsItem destructor of the parent item (which runs before the QObject destructor) destroys the child, which fires a signal to tell the world text editing was canceled, which calls the slot in my already half-destroyed parent item. -
@KroMignon said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
I am trying to solve a crash caused by a slot called during destruction of my class. The problem is, that my own destructor has already run, but QObject's destructor has not yet run, so connections are still active.
IMHO, you have a threading issue here.
For me, to call a slots during destructor, the call have to be started from another thread and the connection type isQt::DirectConnection
.Perhaps you have to look at this?
No, it's quite clearly not a threading issue. Simply put, I have a custom editable text item derived from QGraphicsObject in a Graphics View hierarchy. If the item is destroyed, it notifies that editing was canceled through a signal.
Now I connected this signal to a slot of the text editor's parent item. The QGraphicsItem destructor of the parent item (which runs before the QObject destructor) destroys the child, which fires a signal to tell the world text editing was canceled, which calls the slot in my already half-destroyed parent item.@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
he QGraphicsItem destructor of the parent item (which runs before the QObject destructor) destroys the child, which fires a signal to tell the world text editing was canceled, which calls the slot in my already half-destroyed parent item.
One solution to avoid this loop is to avoid
Qt::DirectConnection
and forceQt::QueuedConnection
for the cancel signal.
So the event is store in eventloop andQObject
destructor will be called before the cancel event.
As instance has been destroyed, the event will be thrown by the QEventLoop. -
I am trying to solve a crash caused by a slot called during destruction of my class. The problem is, that my own destructor has already run, but QObject's destructor has not yet run, so connections are still active.
Since I don't just want to solve this one case, but prevent future cases like this, I'd like to move the disconnection of signals and slots to an earlier time, into a destructor of a custom base class of mine. That way, the offending slot would never be called.
However, I have found no way according to docs to disconnect everything from an object both incoming and outgoing. No list of active connection in QObject or QMetaObject, either. The destructor in QObject does lots of internal stuff, but clearly doesn't use the public-interface disconnect (or similar) methods.
Any ideas how I can safely disconnect everything to AND from and object?
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
I am trying to solve a crash caused by a slot called during destruction of my class. The problem is, that my own destructor has already run, but QObject's destructor has not yet run, so connections are still active.
Often, this can be prevented by using
deleteLater()
to delete your QObjects. This ensures that deletion only occurs after all signals have been processed. -
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
he QGraphicsItem destructor of the parent item (which runs before the QObject destructor) destroys the child, which fires a signal to tell the world text editing was canceled, which calls the slot in my already half-destroyed parent item.
One solution to avoid this loop is to avoid
Qt::DirectConnection
and forceQt::QueuedConnection
for the cancel signal.
So the event is store in eventloop andQObject
destructor will be called before the cancel event.
As instance has been destroyed, the event will be thrown by the QEventLoop.@KroMignon said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
he QGraphicsItem destructor of the parent item (which runs before the QObject destructor) destroys the child, which fires a signal to tell the world text editing was canceled, which calls the slot in my already half-destroyed parent item.
One solution to avoid this loop is to avoid
Qt::DirectConnection
and forceQt::QueuedConnection
for the cancel signal.
So the event is store in eventloop andQObject
destructor will be called before the cancel event.
As instance has been destroyed, the event will be thrown by the QEventLoop.In this case, this would trigger another bug, since the timing of the signal is quite important in the 99 % of cases where the object is not destroyed. But in general, a solution worthy of consideration.
-
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
I am trying to solve a crash caused by a slot called during destruction of my class. The problem is, that my own destructor has already run, but QObject's destructor has not yet run, so connections are still active.
Often, this can be prevented by using
deleteLater()
to delete your QObjects. This ensures that deletion only occurs after all signals have been processed.@JKSH said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
I am trying to solve a crash caused by a slot called during destruction of my class. The problem is, that my own destructor has already run, but QObject's destructor has not yet run, so connections are still active.
Often, this can be prevented by using
deleteLater()
to delete your QObjects. This ensures that deletion only occurs after all signals have been processed.Not here, since GraphicsView will not play along and delete the object anyway...
-
@KroMignon said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
he QGraphicsItem destructor of the parent item (which runs before the QObject destructor) destroys the child, which fires a signal to tell the world text editing was canceled, which calls the slot in my already half-destroyed parent item.
One solution to avoid this loop is to avoid
Qt::DirectConnection
and forceQt::QueuedConnection
for the cancel signal.
So the event is store in eventloop andQObject
destructor will be called before the cancel event.
As instance has been destroyed, the event will be thrown by the QEventLoop.In this case, this would trigger another bug, since the timing of the signal is quite important in the 99 % of cases where the object is not destroyed. But in general, a solution worthy of consideration.
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
In this case, this would trigger another bug, since the timing of the signal is quite important in the 99 % of cases where the object is not destroyed. But in general, a solution worthy of consideration.
You have to made a choice here, because you have a threading issue. Use queued connection is the easiest way, because it is the QEventLoop which will handle it for you.
Another approach, which is not so easy, would be to store
QMetaObject::Connection
returned by eachconnect()
to the critical slots and disconnect then in your destructor. -
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
In this case, this would trigger another bug, since the timing of the signal is quite important in the 99 % of cases where the object is not destroyed. But in general, a solution worthy of consideration.
You have to made a choice here, because you have a threading issue. Use queued connection is the easiest way, because it is the QEventLoop which will handle it for you.
Another approach, which is not so easy, would be to store
QMetaObject::Connection
returned by eachconnect()
to the critical slots and disconnect then in your destructor.@KroMignon said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
In this case, this would trigger another bug, since the timing of the signal is quite important in the 99 % of cases where the object is not destroyed. But in general, a solution worthy of consideration.
You have to made a choice here, because you have a threading issue. Use queued connection is the easiest way, because it is the QEventLoop which will handle it for you.
Another approach, which is not so easy, would be to store
QMetaObject::Connection
returned by eachconnect()
to the critical slots and disconnect then in your destructor.Why do you believe so firmly it's a threading issue? It isn't, I see the call stack and the parallel stacks in debugger. Also, the behavior is easily explained for any QGraphicsObject, because the QGraphicsItem will delete it's child directly in the destructor, before the destructor of QObject runs (remember that you always have to derive from QObject first, so it's the last to destruct)
EDIT: Also, I never used Qt::DirectConnection anywhere in 10 years of coding. So if it was multithreaded, the slot would be called queued.
-
@KroMignon said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
In this case, this would trigger another bug, since the timing of the signal is quite important in the 99 % of cases where the object is not destroyed. But in general, a solution worthy of consideration.
You have to made a choice here, because you have a threading issue. Use queued connection is the easiest way, because it is the QEventLoop which will handle it for you.
Another approach, which is not so easy, would be to store
QMetaObject::Connection
returned by eachconnect()
to the critical slots and disconnect then in your destructor.Why do you believe so firmly it's a threading issue? It isn't, I see the call stack and the parallel stacks in debugger. Also, the behavior is easily explained for any QGraphicsObject, because the QGraphicsItem will delete it's child directly in the destructor, before the destructor of QObject runs (remember that you always have to derive from QObject first, so it's the last to destruct)
EDIT: Also, I never used Qt::DirectConnection anywhere in 10 years of coding. So if it was multithreaded, the slot would be called queued.
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
EDIT: Also, I never used Qt::DirectConnection anywhere in 10 years of coding. So if it was multithreaded, the slot would be called queued.
If you are not specifying the connection type (
Qt::AutoConnection
) and sender/emitter are in same thread, it is same are usingQt::DirectConnection
.
So now you have an issue with this because signals are emitted during execution of your destructor and those signals are executing slots of your currently destroyed instance.
If you have used Qt::QueuedConnection, you would not have this issue.I call this "threading issue", and yes it is not the right description. I apologize.
-
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
EDIT: Also, I never used Qt::DirectConnection anywhere in 10 years of coding. So if it was multithreaded, the slot would be called queued.
If you are not specifying the connection type (
Qt::AutoConnection
) and sender/emitter are in same thread, it is same are usingQt::DirectConnection
.
So now you have an issue with this because signals are emitted during execution of your destructor and those signals are executing slots of your currently destroyed instance.
If you have used Qt::QueuedConnection, you would not have this issue.I call this "threading issue", and yes it is not the right description. I apologize.
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
@JKSH said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
Often, this can be prevented by using
deleteLater()
to delete your QObjects. This ensures that deletion only occurs after all signals have been processed.Not here, since GraphicsView will not play along and delete the object anyway...
Ah, I see the problem now.
@KroMignon said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
I call this "threading issue", and yes it is not the right description. I apologize.
I'd say "sequencing issue" is a more correct term since everything is occurring on the same thread.
Another approach, which is not so easy, would be to store
QMetaObject::Connection
returned by eachconnect()
to the critical slots and disconnect then in your destructor.I can't think of any nice ways to fix @Asperamanca's problem if he wants to avoid
Qt::QueuedConnection
too. This solution is probably the best. -
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
@JKSH said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
Often, this can be prevented by using
deleteLater()
to delete your QObjects. This ensures that deletion only occurs after all signals have been processed.Not here, since GraphicsView will not play along and delete the object anyway...
Ah, I see the problem now.
@KroMignon said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
I call this "threading issue", and yes it is not the right description. I apologize.
I'd say "sequencing issue" is a more correct term since everything is occurring on the same thread.
Another approach, which is not so easy, would be to store
QMetaObject::Connection
returned by eachconnect()
to the critical slots and disconnect then in your destructor.I can't think of any nice ways to fix @Asperamanca's problem if he wants to avoid
Qt::QueuedConnection
too. This solution is probably the best.@JKSH
Well, I don't like the QueuedConnection solution because it would open a can of worms in order to close a different can of worms...Good solutions would be the ability to disconnect my slots (which disconnect() doesn't offer), or an ability to block my slots (there is a feature to block my signals, but not a similar one for slots).
In the end, I made do with the non-generic, specific solution of manually disconnecting the offending slots in my own destructor.
-
@JKSH
Well, I don't like the QueuedConnection solution because it would open a can of worms in order to close a different can of worms...Good solutions would be the ability to disconnect my slots (which disconnect() doesn't offer), or an ability to block my slots (there is a feature to block my signals, but not a similar one for slots).
In the end, I made do with the non-generic, specific solution of manually disconnecting the offending slots in my own destructor.
@Asperamanca said in Disconnect all incoming and outgoing connections from QObject-derived class manually:
In the end, I made do with the non-generic, specific solution of manually disconnecting the offending slots in my own destructor.
It is normal that you don't have a generic solution, because, IMHO your code construction is not very clean. Updating a class when calling class destructor is a kind of "binding loop" issue.
You can only disconnect signals from a class instance, because signal is the starting point. A class instance does not known which signal is connect to his slots, this made no sense, for example how should functor/lambda connection be recorded?
If you want to disconnect slots, you have to store
connect()
result and use it to disconnect the slots.