Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-52543

Difference in behavior using the new QObject::connect syntax

    XMLWordPrintable

Details

    • Bug
    • Resolution: Invalid
    • P3: Somewhat important
    • None
    • 5.4.1
    • Core: Object Model
    • None

    Description

      We've had a crash bug that has highlighted an inconsistency after a changing a connection from the syntax:

      connect(foo, SIGNAL(mySignal()), bar, SLOT(mySlot()));
      

      to:

      connect(foo, &Foo::mySignal, bar, &Foo::mySlot);
      

      Consider the following situation:

      class Foo : public QWidget
      {
          Q_OBJECT
      public:
          Foo( QWidget* parent = 0 ) : QWidget(parent) { }
          ~Foo() { emit mySignal(); }
      public slots:
          void mySlot() { qDebug() << "mySlot is called"; };
      signals:
          void mySignal();
      };
      
      Foo* bar = new Foo;
      Foo* foo = new Foo(bar);
      connect(foo, &Foo::mySignal, bar, &Foo::mySlot); // A. mySlot is called
      //connect(foo, SIGNAL(mySignal()), bar, SLOT(mySlot())); // B. replace connection with this and observe that mySlot isn't called
      delete bar;
      

      To explain what's happening:

      1. When you delete object bar, foo will get deleted in bar::~QWidget. This happens after bar::~Foo.
      2. When we switched to the new connection syntax (A), Qt directly calls bar::myslot, even though the ~Foo destructor has been run. In our setup this resulted in a crash as the slot was using some deleted members.
      3. However if you switch this to use the old connection syntax (B), when foo::mySignal fires, it will try and call bar::mySlot. However, this internally ends up invoking the virtual function Foo::qt_metacall on bar, and because bar::~Foo has already been executed, the vtable directs it to QWidget::qt_metacall instead. This results in no call to mySlot() as it doesn't find a slot with a matching ID. This behavior is good in that it doesn't crash, but I do think that there should be a warning here because the function wasn't actually invoked:

      qobject.cpp, line 3731. metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv); // should warn if return value >= 0.
      

      Overall, this is a fairly subtle difference in behavior when using the new connection syntax, but an important one. There may be some mechanism to get consistent behavior (e.g. checking what the metaobject is at time of invocation), but at the least, I'd advise that this difference is documented.

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            ogoffart Olivier Goffart (Woboq GmbH)
            trcki Patrick Wadsworth
            Votes:
            1 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes