Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Weird connection between QComboBox, QBasicTimer and static object initialization.

Weird connection between QComboBox, QBasicTimer and static object initialization.

Scheduled Pinned Locked Moved Unsolved General and Desktop
qcomboboxqbasictimercrash
9 Posts 4 Posters 1.0k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • C Offline
    C Offline
    CJha
    wrote on 23 Feb 2023, 13:35 last edited by CJha
    #1

    Hi, I am creating a basic widget class:

    widget.h

    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        static Widget& inst();
        Widget();
        ~Widget() override = default;
    
    private:
        Ui::Form ui;
    };
    

    widget.cpp

    Widget& Widget::inst()
    {
        static Widget instance;
        return instance;
    }
    
    Widget::Widget() { ui.setupUi(this); }
    

    The Widget class has a UI with just a QComboBox with 2 items in it, it looks like this:
    086a52ff-2db6-4371-84c8-e8c805aec18c-image.png

    The MainWindow class has a UI with just a QPushButton named pushButton to show the Widget class object ui.
    mainwindow.h

    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(Widget* widPtr, QWidget *parent = nullptr);
        ~MainWindow();
    
    private:
        Ui::MainWindowClass ui;
        QPointer<Widget> wid{nullptr};
    
    public slots:
        void on_pushButton_clicked();
    };
    

    mainwindow.cpp

    MainWindow::MainWindow(Widget* widPtr, QWidget* parent)
        : QMainWindow(parent)
    {
        ui.setupUi(this);
        wid = widPtr;
    }
    
    MainWindow::~MainWindow() {}
    
    void MainWindow::on_pushButton_clicked()
    {
        if(!wid.isNull())
            wid->show();
    }
    

    If I do like this in my main function:

    int main(int argc, char* argv[])
    {
        QApplication a(argc, argv);
        auto wid{&Widget::inst()}; // getting widget instance, this is where the widget is created
        MainWindow w{wid};
        w.show();
        return a.exec();
    }
    

    And if I click on the QComboBox in the Widget UI then I get an error only when I close the application:

    QBasicTimer::start: QBasicTimer can only be used with threads started with QThread
    Exception thrown at 0x00007FFE20BA447B (qwindowsd.dll) in ComboBox_Test.exe: 0xC0000005: Access violation reading location 0x0000000000000000.
    

    However, if I do like this in the main function:

    int main(int argc, char* argv[])
    {
        QApplication a(argc, argv);
        Widget wid; // creating widget using normal constructor
        MainWindow w{&wid};
        w.show();
        return a.exec();
    }
    

    I do not get the error while closing.

    There are a few peculier thing about the error:

    • Only happens with QComboBox and only if I click it at least once during the program execution. I have tested the same setup but with QSpinBox, QLineEdit, QPushButton, and none of these throw any kind of error when closing the app.
    • When the rror occurs I also get a warning about QBasicTimer although I am using no timers at all.
    • Error happens after the destructor for both Widget and MainWindow have been called and only after it I get the warning about QBasicTimer
    • This problem was not present around 3 weeks ago with Qt 6.3.0. Now this problem is appearing with both Qt 6.3.0 and Qt 6.4.2. I have updated both versions of Qt last week.

    What is so peculiar about QComboBox? Why is it causing the QBasicTimer to issue a warning? Why the error only occurs when I do a static initialization but not in normal construction even though the construction and destruction sequence and timings are same in both cases? So many questions...

    J 1 Reply Last reply 23 Feb 2023, 14:16
    0
    • C CJha
      23 Feb 2023, 13:35

      Hi, I am creating a basic widget class:

      widget.h

      class Widget : public QWidget
      {
          Q_OBJECT
      
      public:
          static Widget& inst();
          Widget();
          ~Widget() override = default;
      
      private:
          Ui::Form ui;
      };
      

      widget.cpp

      Widget& Widget::inst()
      {
          static Widget instance;
          return instance;
      }
      
      Widget::Widget() { ui.setupUi(this); }
      

      The Widget class has a UI with just a QComboBox with 2 items in it, it looks like this:
      086a52ff-2db6-4371-84c8-e8c805aec18c-image.png

      The MainWindow class has a UI with just a QPushButton named pushButton to show the Widget class object ui.
      mainwindow.h

      class MainWindow : public QMainWindow
      {
          Q_OBJECT
      
      public:
          MainWindow(Widget* widPtr, QWidget *parent = nullptr);
          ~MainWindow();
      
      private:
          Ui::MainWindowClass ui;
          QPointer<Widget> wid{nullptr};
      
      public slots:
          void on_pushButton_clicked();
      };
      

      mainwindow.cpp

      MainWindow::MainWindow(Widget* widPtr, QWidget* parent)
          : QMainWindow(parent)
      {
          ui.setupUi(this);
          wid = widPtr;
      }
      
      MainWindow::~MainWindow() {}
      
      void MainWindow::on_pushButton_clicked()
      {
          if(!wid.isNull())
              wid->show();
      }
      

      If I do like this in my main function:

      int main(int argc, char* argv[])
      {
          QApplication a(argc, argv);
          auto wid{&Widget::inst()}; // getting widget instance, this is where the widget is created
          MainWindow w{wid};
          w.show();
          return a.exec();
      }
      

      And if I click on the QComboBox in the Widget UI then I get an error only when I close the application:

      QBasicTimer::start: QBasicTimer can only be used with threads started with QThread
      Exception thrown at 0x00007FFE20BA447B (qwindowsd.dll) in ComboBox_Test.exe: 0xC0000005: Access violation reading location 0x0000000000000000.
      

      However, if I do like this in the main function:

      int main(int argc, char* argv[])
      {
          QApplication a(argc, argv);
          Widget wid; // creating widget using normal constructor
          MainWindow w{&wid};
          w.show();
          return a.exec();
      }
      

      I do not get the error while closing.

      There are a few peculier thing about the error:

      • Only happens with QComboBox and only if I click it at least once during the program execution. I have tested the same setup but with QSpinBox, QLineEdit, QPushButton, and none of these throw any kind of error when closing the app.
      • When the rror occurs I also get a warning about QBasicTimer although I am using no timers at all.
      • Error happens after the destructor for both Widget and MainWindow have been called and only after it I get the warning about QBasicTimer
      • This problem was not present around 3 weeks ago with Qt 6.3.0. Now this problem is appearing with both Qt 6.3.0 and Qt 6.4.2. I have updated both versions of Qt last week.

      What is so peculiar about QComboBox? Why is it causing the QBasicTimer to issue a warning? Why the error only occurs when I do a static initialization but not in normal construction even though the construction and destruction sequence and timings are same in both cases? So many questions...

      J Offline
      J Offline
      JonB
      wrote on 23 Feb 2023, 14:16 last edited by JonB
      #2

      @CJha
      While you await someone's answer as to exact reason [ @Christian-Ehrlicher will probably like this one :) ]. Why do you do any of this static stuff, especially since it's causing a problem? Likely there would not be an issue if you did not? Your second main function is the way everybody else would write it.

      C 1 Reply Last reply 23 Feb 2023, 14:23
      2
      • J JonB
        23 Feb 2023, 14:16

        @CJha
        While you await someone's answer as to exact reason [ @Christian-Ehrlicher will probably like this one :) ]. Why do you do any of this static stuff, especially since it's causing a problem? Likely there would not be an issue if you did not? Your second main function is the way everybody else would write it.

        C Offline
        C Offline
        CJha
        wrote on 23 Feb 2023, 14:23 last edited by
        #3

        @JonB I do it to create a Singleton, and I create a singleton because Qt itself creates a singleton of QApplication. The class object that I create in my main function before MainWindow deals a lot with qApp pointer and provides customized communication with the rest of the code, since QApplication is a singleton it makes sense to make this class a singleton as well. This is the only class I have as a singleton in the entire application.

        J 1 Reply Last reply 23 Feb 2023, 14:29
        0
        • C CJha
          23 Feb 2023, 14:23

          @JonB I do it to create a Singleton, and I create a singleton because Qt itself creates a singleton of QApplication. The class object that I create in my main function before MainWindow deals a lot with qApp pointer and provides customized communication with the rest of the code, since QApplication is a singleton it makes sense to make this class a singleton as well. This is the only class I have as a singleton in the entire application.

          J Offline
          J Offline
          JonB
          wrote on 23 Feb 2023, 14:29 last edited by JonB
          #4

          @CJha
          OK, at least you have a reason :)

          Don't you think the reason it's erroring, under whatever circumstances, might be to do with when your singleton instance is getting destructed? If that comes after, say, the QApplication a instance is destroyed might that be the behaviour you see? You might connect to the QObject::destroyed signal on the widget and on the app to see if this might be a factor?

          C 1 Reply Last reply 23 Feb 2023, 14:40
          1
          • J JonB
            23 Feb 2023, 14:29

            @CJha
            OK, at least you have a reason :)

            Don't you think the reason it's erroring, under whatever circumstances, might be to do with when your singleton instance is getting destructed? If that comes after, say, the QApplication a instance is destroyed might that be the behaviour you see? You might connect to the QObject::destroyed signal on the widget and on the app to see if this might be a factor?

            C Offline
            C Offline
            CJha
            wrote on 23 Feb 2023, 14:40 last edited by
            #5

            @JonB Thanks! I was checking for the destructor sequence of Widget and MainWindow but never thought that the QApplication object was being destroyed before the Widget. And you are right, the QApplication is getting destroyed first before the Widget.

            I still don't understand why just clicking on only QComboBox will cause an error and not anything else like QSpinBox, QLineEdit, etc.

            J 1 Reply Last reply 23 Feb 2023, 14:45
            0
            • C CJha
              23 Feb 2023, 14:40

              @JonB Thanks! I was checking for the destructor sequence of Widget and MainWindow but never thought that the QApplication object was being destroyed before the Widget. And you are right, the QApplication is getting destroyed first before the Widget.

              I still don't understand why just clicking on only QComboBox will cause an error and not anything else like QSpinBox, QLineEdit, etc.

              J Offline
              J Offline
              JonB
              wrote on 23 Feb 2023, 14:45 last edited by JonB
              #6

              @CJha
              QComboBox I would guess will create a timer of some kind (that QBasicTimer?) to handle opening/closing the popup or something. Then something like that doesn't get destroyed till after the app with your singleton? The other widgets probably don't create one. Something like that?

              C 1 Reply Last reply 23 Feb 2023, 14:50
              2
              • J JonB
                23 Feb 2023, 14:45

                @CJha
                QComboBox I would guess will create a timer of some kind (that QBasicTimer?) to handle opening/closing the popup or something. Then something like that doesn't get destroyed till after the app with your singleton? The other widgets probably don't create one. Something like that?

                C Offline
                C Offline
                CJha
                wrote on 23 Feb 2023, 14:50 last edited by
                #7

                @JonB Makes sense, better than no reason at all ;)
                I will completely remove the singleton and deal with the qApp separately.

                1 Reply Last reply
                0
                • C Offline
                  C Offline
                  Chris Kawa
                  Lifetime Qt Champion
                  wrote on 23 Feb 2023, 15:43 last edited by
                  #8

                  The general lifetime rule is that no QObject will live past the destruction of the application object. That basically means no static QObjects at all.

                  It's a blanket statement rule for all QObjects. The behavior, if you break it, is undefined. Some objects might actually make it, some won't, depending on what they do in their destructor. That's why QComboBox crashes while some other stuff might not. But in any case you shouldn't do it, even if something appears to work, because it might stop in next Qt version, on another platform or if the moon is in particular phase.

                  The reason this works

                  QApplication a(argc, argv);
                  Widget wid;
                  

                  is that you create both objects on the stack and it is guaranteed by the language that they will be destroyed in reverse order of creation, so wid will be destroyed before a.

                  Static objects are destroyed in unspecified order at the end of the app, past the return point from the main function, so a singleton like yours is not valid.

                  You can make a QObject singleton if you really want to like this:

                  Widget& Widget::inst()
                  {
                      static Widget* instance = nullptr;
                      if (!instance)
                      {
                          instance = new Widget();
                          QObject::connect(qApp, &QApplication::aboutToQuit, instance, &Widget::deleteLater);
                      }
                      return *instance;
                  }
                  

                  but keep in mind that this is a bit dangerous if some code calls it out of the lifetime of the application object.
                  In general singleton pattern doesn't go too well with QObjects.

                  C 1 Reply Last reply 23 Feb 2023, 16:11
                  3
                  • C Chris Kawa
                    23 Feb 2023, 15:43

                    The general lifetime rule is that no QObject will live past the destruction of the application object. That basically means no static QObjects at all.

                    It's a blanket statement rule for all QObjects. The behavior, if you break it, is undefined. Some objects might actually make it, some won't, depending on what they do in their destructor. That's why QComboBox crashes while some other stuff might not. But in any case you shouldn't do it, even if something appears to work, because it might stop in next Qt version, on another platform or if the moon is in particular phase.

                    The reason this works

                    QApplication a(argc, argv);
                    Widget wid;
                    

                    is that you create both objects on the stack and it is guaranteed by the language that they will be destroyed in reverse order of creation, so wid will be destroyed before a.

                    Static objects are destroyed in unspecified order at the end of the app, past the return point from the main function, so a singleton like yours is not valid.

                    You can make a QObject singleton if you really want to like this:

                    Widget& Widget::inst()
                    {
                        static Widget* instance = nullptr;
                        if (!instance)
                        {
                            instance = new Widget();
                            QObject::connect(qApp, &QApplication::aboutToQuit, instance, &Widget::deleteLater);
                        }
                        return *instance;
                    }
                    

                    but keep in mind that this is a bit dangerous if some code calls it out of the lifetime of the application object.
                    In general singleton pattern doesn't go too well with QObjects.

                    C Online
                    C Online
                    Christian Ehrlicher
                    Lifetime Qt Champion
                    wrote on 23 Feb 2023, 16:11 last edited by
                    #9

                    @Chris-Kawa said in Weird connection between QComboBox, QBasicTimer and static object initialization.:

                    In general singleton pattern doesn't go too well with QObjects.

                    ... and is not needed in most cases - this one here is one of the most cases where a singleton is not needed

                    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                    Visit the Qt Academy at https://academy.qt.io/catalog

                    1 Reply Last reply
                    2

                    8/9

                    23 Feb 2023, 15:43

                    • Login

                    • Login or register to search.
                    8 out of 9
                    • First post
                      8/9
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved