April 25, 2012

Davita Davita
Lab Rat
49 posts

[Solved] crash. QObject::connect in a constructor of a static object instance.


I’m trying to find out why my app crashes for the whole day. A picture worth thousands of words, so take a look at this code:

  1. class SandboxedAppStat : public QObject
  2. {
  3.     Q_OBJECT
  5. private slots:
  6.     void pidsTimerTimeout();
  8. public:
  9.     QTimer m_PidsTimer;
  11.     SandboxedAppStat(QObject *parent = NULL);
  12. };
  15. void SandboxedAppStat::pidsTimerTimeout()
  16. {
  17.     qDebug() << "whatever";
  18. }
  20. SandboxedAppStat::SandboxedAppStat(QObject *parent)
  21.     : QObject(parent)
  22. {
  23.         bool b = QObject::connect(&m_PidsTimer), SIGNAL(timeout()), this, SLOT(pidsTimerTimeout()));
  24.         m_PidsTimer.start(500);
  25. }

  1. class SandboxedApp : public QObject
  2. {
  3.     Q_OBJECT
  5. private:
  6.     static SandboxedAppStat SandboxedAppStat1;
  7. };
  10. SandboxedAppStat SandboxedApp::SandboxedAppStat1;

Actually what I’m trying to do, is to simulate static constructor behavior in C++. I want

  1. QObject::connect(&m_PidsTimer), SIGNAL(timeout()), this, SLOT(pidsTimerTimeout()));
  2. m_PidsTimer.start(500);

to be called as soon as the static member SandboxedAppStat1 initializes. That’s why the code shown above is in the constructor of SandboxedAppStat.
However, my problem is that when I run the program, it crashes as soon as it reaches the line

  1. connect(&m_PidsTimer), SIGNAL(timeout()), this, SLOT(pidsTimerTimeout()));

with error code c0000005 (access violation I guess).
here’s the screenshot http://dl.dropbox.com/u/3055964/Untitled.gif

If I declare SandboxedAppStat as a non static variable, then there is no crash and no errors. everything works fine.
First I thought that crash reason could be the fact that, static members are initialized too early for QObject::connect to be able to be called, that’s why I updated SandboxedAppStat constructor with the following code:

  1.     auto *t = this;
  2.     QtConcurrent::run([&] () {
  3.         Sleep(3000);
  4.         bool b = QObject::connect(&(t->m_PidsTimer), SIGNAL(timeout()), t, SLOT(pidsTimerTimeout()));
  5.         t->m_PidsTimer.start(500);
  6.     });

As you can see, QObject::connect executes after 3 seconds when static SanboxedAppStat is initialized, but this didn’t help either, the program crashes after 3 seconds.
I’m really confused, I don’t understand what can be the cause of this problem. Can’t we use signal/slots in a static object instances?

I’m using Qt 4.8.0 with MSVC 2010.


5 replies

April 26, 2012

alexisdm alexisdm
Lab Rat
142 posts

For the first method, the problem might be that the metaobject needed for connecting the slot is not yet initialized (See the static order initialization fiasco in the C++ FAQ [parashift.com]).

It doesn’t crash with gcc on linux, but it prints the error:

  1. QObject::startTimer: QTimer can only be used with threads started with QThread

And for the second method, with the lambda, I think the crash is caused by the variable t going out of scope, and not pointing to a valid pointer at the time the connect call occurs. You could pass it as a binded parameter to run:

  1. QtConcurrent::run([&] (decltype(this) t) {
  2.         bool b = QObject::connect(&(t->m_PidsTimer), SIGNAL(timeout()), t, SLOT(pidsTimerTimeout()));
  3.         t->m_PidsTimer.start(500);}
  4.     , this);

April 26, 2012

Davita Davita
Lab Rat
49 posts

@alexisdm thank you for your answer. You were right about the lambdas, I followed your suggestion and didn’t had a crash after that.
However, about static order initialization, as far as I’m aware, this can occur only if a static object/function tries to access another static object in different compilation unit. Does this mean that Qt meta object stuff is accessing my static member from a static function? And if so, why? what’s the reason behind this?


April 26, 2012

Davita Davita
Lab Rat
49 posts

BTW, here’s a simple project consisting of only one header and one source file to reproduce the problem. http://dl.dropbox.com/u/3055964/untitled1.zip

April 26, 2012

alexisdm alexisdm
Lab Rat
142 posts

The static data being accessed is the meta information generated by the moc for your SandboxedAppStat class, in the file moc_yourfilename.cpp.

You could try printing the class name to confirm the problem:

  1. SandboxedAppStat::SandboxedAppStat(QObject *parent)
  2.     : QObject(parent)
  3. {    
  4.      std::cout << Q_FUNC_INFO << std::endl; // just to confirm we entered the function
  5.      std::cout << "class name: " << SandboxedAppStat::staticMetaObject.className() << std::endl;
  6. }

I tested and it does crash with msvc2010, but works fine with gcc.

April 27, 2012

Davita Davita
Lab Rat
49 posts

@alexisdm thank you very much, your post saved me :)

  ‹‹ Purple Error in Widget Project      QGraphicsTextItem and path ››

You must log in to post a reply. Not a member yet? Register here!