1

I have an application with a QMdiArea. There's some incoming and outgoing signals connected to the widget in the currently active subwindow. Whenever the active subwindow changes I want to disconnect all the connections to the previously active widget and connect to the newly activated widget. As such:

//Function connected to QMdiArea::subWindowActivated...
void
MainWindow::SubWindowActivated(QMdiSubWindow* subWindow)
{
    auto activeWidget{ qobject_cast<MyWidget*>(subWindow->widget()) };
    if (activeWidget == mPreviouslyActiveWidget)
    {
        return;
    }

    //disconnect all incoming and outgoing signals between previously active widget and this.
    disconnect(this, nullptr, mPreviouslyActiveWidget, nullptr); 
    disconnect(mPreviouslyActiveWidget, nullptr, this, nullptr);

    //re-establish connections to activeWidget ... removed for brevity
    mPreviouslyActiveWidget = activeWidget;
}

It's possible that the subwindow changed because the previous subwindow was closed by the user and thus no longer exists/is deleted by the QMdiArea. In that case I would be calling the disconnect functions whith mPreviouslyActiveWidget pointing to a deleted object. Is this a problem? Will the call simply fail and return false or is this undefined ?

Unimportant
  • 2,076
  • 14
  • 19
  • That depends on whether `disconnect` attempts to access the object or not; check the documentation. You *could* read the code, but relying on undocumented implementation details is usually the first step towards headaches. The safe method is to keep track of whether the object exists. – molbdnilo Nov 24 '21 at 10:13
  • 3
    `mPreviouslyActiveWidget` is effectively a dangling pointer in such cases so you have undefined behaviour. Can I suggest that rather than use `QWidget *mPreviouslyActiveWidget` you use something like [`QPointer mPreviouslyActiveWidget`](https://doc.qt.io/qt-5/qpointer.html) instead. That way you can check the validity of `mPreviouslyActiveWidget` before accessing/dereferencing it. – G.M. Nov 24 '21 at 10:13
  • 1
    @molbdnilo Yes, that's why I'm asking. Perhaps someone has deeper knowledge of Qt's internals. For all I know `disconnect` simply searches some container with connections for that pointer value and removes entries when found. Which would be safe, even with a dangling pointer. – Unimportant Nov 24 '21 at 10:15
  • 2
    Note that if `mPreviouslyActiveWidget` has been deleted then all connections associated with it will already have been removed/destroyed by its [destructor](https://doc.qt.io/qt-5/qobject.html#dtor.QObject). – G.M. Nov 24 '21 at 10:20
  • If your `disconnect()` function dereferences that pointer [i.e. attempts to use the destroyed object (e.g. calls non-static member functions, access non-static members, destroys it a second time)] the behaviour is undefined. If it simply compares the value of that pointer for equality with other pointers (e.g as part of removing a pointer with the same value from a list) then the behaviour is not undefined. – Peter Nov 24 '21 at 11:37
  • You are trying to find a solution for when `mPreviouslyActiveWidget` is a dangling pointer (pointing to something that is already `delete`ed). That seems like bad design in the first place. Try to have some code run when the subwindow is destroyed (i.e. connect to [QObject::destroyed](https://doc.qt.io/qt-5/qobject.html#destroyed) and set `mPreviouslyActiveWidget` to NULL in this case. Then you can just skip the `disconnect` calls if there is no previous widget. – SebDieBln Dec 01 '21 at 11:48

0 Answers0