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.
QtWS25 Last Chance

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.
  • CJhaC Offline
    CJhaC Offline
    CJha
    wrote on 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...

    JonBJ 1 Reply Last reply
    0
    • CJhaC CJha

      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...

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on 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.

      CJhaC 1 Reply Last reply
      2
      • JonBJ JonB

        @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.

        CJhaC Offline
        CJhaC Offline
        CJha
        wrote on 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.

        JonBJ 1 Reply Last reply
        0
        • CJhaC CJha

          @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.

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on 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?

          CJhaC 1 Reply Last reply
          1
          • JonBJ JonB

            @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?

            CJhaC Offline
            CJhaC Offline
            CJha
            wrote on 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.

            JonBJ 1 Reply Last reply
            0
            • CJhaC CJha

              @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.

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on 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?

              CJhaC 1 Reply Last reply
              2
              • JonBJ JonB

                @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?

                CJhaC Offline
                CJhaC Offline
                CJha
                wrote on 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
                • Chris KawaC Offline
                  Chris KawaC Offline
                  Chris Kawa
                  Lifetime Qt Champion
                  wrote on 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.

                  Christian EhrlicherC 1 Reply Last reply
                  3
                  • Chris KawaC Chris Kawa

                    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.

                    Christian EhrlicherC Offline
                    Christian EhrlicherC Offline
                    Christian Ehrlicher
                    Lifetime Qt Champion
                    wrote on 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

                    • Login

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