Qt destructor call for closed widget

17,156

Solution 1

Setting Qt::WA_DeleteOnClose means qt can delete anytime after you call close() because qt uses deleteLater() internally. You can ensure the deletion using QObject::destroyed() signal.

Solution 2

QCoreApplication::processEvents explicitly skips delete on close events. You need to pass QEventLoop::DeferredDeletion to processEvents(). i.e. QCoreApplication::processEvents(QEventLoop::DeferredDeletion);

Share:
17,156
axe
Author by

axe

Updated on July 20, 2022

Comments

  • axe
    axe almost 2 years

    There is application that handles text commands. I have a Qt widget that is closed with some close * command. Qt::WA_DeleteOnClose attribute is set for that widget, it receives closeEvent, but destructor for that object is called later (I guess on idle). If I have two commands close *; get something; the program crashes because get something is called before destructor for that widget, so it tries to access data deleted by close * command. How can I force Qt to call destructors? QCoreApplication::processEvents() after close command doesn't help. I've got this problem after changing qt version to 4.7.2 from 4.3.3. There is no multithreading here.

    Thanks in advance.

    added

    Here is the code example.

    test *t = new test();
    t->show();
    std::cout << "before deleteLater()" << std::endl;
    t->deleteLater();
    std::cout << "after deleteLater()" << std::endl;
    QCoreApplication::sendPostedEvents();
    QCoreApplication::processEvents();
    std::cout << "after processEvents()" << std::endl;
    

    test class is derived from QDialog. It prints test() in constructor and ~test() in destructor. This code gives the following output

    test()
    before deleteLater()
    after deleteLater()
    after processEvents()
    ~test()
    

    According to Qt documentation it should delete the object before last cout, am I right? Looks like a bug in Qt, does anybody know anything about it? Any workaround?

    I asked the question in Qt mailing list, but still waiting for an answer.

    Thanks.

    one more update

    This code

    Dialog::~Dialog() {
        std::cout << "~test()" << std::endl;
    }
    
    int main(int argc, char* argv[]) {
        QApplication app(argc, argv);
        Dialog* dlg = new Dialog();
        dlg->setAttribute(Qt::WA_DeleteOnClose);
        dlg->show();
        dlg->close();
        std::cout << "before sendPostedEvents()" << std::endl;
        QCoreApplication::sendPostedEvents();
        std::cout << "after sendPostedEvents()" << std::endl;
        return app.exec();
    }
    

    prints this

    before sendPostedEvents()
    after sendPostedEvents()
    ~test()
    

    but as soon as I add closeEvent handler and call deleteLater() in that handler function sendPostedEvents starts deleting deferred objects.

    void Dialog::closeEvent(QCloseEvent* ev) {
        deleteLater();
        QWidget::closeEvent(ev);
    }
    

    prints this before sendPostedEvents() ~test() after sendPostedEvents()

    Can anybody explain what the hell is going on there? Is it just a bug? Can I use that as a workaround?

    How does this work? Shouldn't Qt call deleteLater() automatically, after closeEvent is accepted if CloseOnDelete attribute is set?

  • axe
    axe over 12 years
    I was able to fix it by adding deleteLater() function call for that widget in closeEvent function. But I would like to understand the solution. Could you please explain that in more details or provide a link that explains that technique?
  • axe
    axe over 12 years
    I want to ensure that Qt will delete the at the moment I finished executing my first command. How can I make it?
  • useraged
    useraged over 12 years
    If you can close it you can delete it too. Don't set Qt::WA_DeleteOnClose flag and simply delete it. You'll be sure then.
  • axe
    axe over 12 years
    The application is really huge, then I would need to ensure that I delete it from everywhere where close is called. I wouldn't like to make much changes there. This might result in memory leak. Isn't it possible to force Qt to delete the objects marked as DeleteOnClose?
  • useraged
    useraged over 12 years
    According to qt documentation, you can use sendPostedEvents() too. doc.qt.nokia.com/latest/qcoreapplication.html#processEvents
  • axe
    axe over 12 years
    processEvents() and sendPostedEvents() doesn't help. If I switch to manual deletion it works fine, but when I replace delete obj with obj->deleteLater(); QCoreApplication::sendPostedEvents(); or processEvents() it doesn't work again.
  • useraged
    useraged over 12 years
    Manual deletion does not result memorly leaks if code is properly written. Normally processEvents should delete that object. Because deleteLater sends an event to widget and calling processEvents with no argument should handles all posted events. It can be a bug in qt. I think you should write this problem to [email protected] maillist.
  • axe
    axe over 12 years
    It can result to memory leak, because I'm not sure where it can be closed from, to put delete everywhere. And yes, code is not properly written :) I'll try nokia forums. Thanks a lot for your help.