[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_OBJECT

    private 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_OBJECT

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

    @ 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 :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.