[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:
@class SandboxedAppStat : public QObject
{
Q_OBJECTprivate slots:
void pidsTimerTimeout();public:
QTimer m_PidsTimer;SandboxedAppStat(QObject *parent = NULL);
};
void SandboxedAppStat::pidsTimerTimeout()
{
qDebug() << "whatever";
}SandboxedAppStat::SandboxedAppStat(QObject *parent)
: QObject(parent)
{
bool b = QObject::connect(&m_PidsTimer), SIGNAL(timeout()), this, SLOT(pidsTimerTimeout()));
m_PidsTimer.start(500);
}@@class SandboxedApp : public QObject
{
Q_OBJECTprivate:
static SandboxedAppStat SandboxedAppStat1;
};SandboxedAppStat SandboxedApp::SandboxedAppStat1;
@Actually what I'm trying to do, is to simulate static constructor behavior in C++. I want
@QObject::connect(&m_PidsTimer), SIGNAL(timeout()), this, SLOT(pidsTimerTimeout()));
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 @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.gifIf 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:@ auto *t = this;
QtConcurrent::run([&] () {
Sleep(3000);
bool b = QObject::connect(&(t->m_PidsTimer), SIGNAL(timeout()), t, SLOT(pidsTimerTimeout()));
t->m_PidsTimer.start(500);
});
@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.
Thanks
-
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":http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14).
It doesn't crash with gcc on linux, but it prints the error:
@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:
@QtConcurrent::run([&] (decltype(this) t) {
bool b = QObject::connect(&(t->m_PidsTimer), SIGNAL(timeout()), t, SLOT(pidsTimerTimeout()));
t->m_PidsTimer.start(500);}
, this);
@ -
@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?Thanks
-
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
-
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:
@SandboxedAppStat::SandboxedAppStat(QObject *parent)
: QObject(parent)
{
std::cout << Q_FUNC_INFO << std::endl; // just to confirm we entered the function
std::cout << "class name: " << SandboxedAppStat::staticMetaObject.className() << std::endl;
}@
I tested and it does crash with msvc2010, but works fine with gcc. -
@alexisdm thank you very much, your post saved me :)