Search code examples
c++qt6

How to prevent lifetime issues between completion of background task and UI in Qt


When using QtConcurrent::run to run code in the background from a UI the QFuture::then(QObject *context, Function &&function) can be used to update the UI because you can pass the window object as context to make function execute on the GUI thread. This is very convenient however there is one problem. When the window is closed and it is deallocated before the background task completes the program will crash when the task completes because the context passed to then is no longer valid.

Is there an easy way to prevent this problem? I know a QFutureWatcher can be used but that object would need to be added to the window class and one would be needed for every asynchronous task the window can execute which is cumbersome.


Solution

  • One simple option would be to use a QPointer to track/monitor the QWidget of interest. A copy of the QPointer can be captured by whatever lambdas or functors are used by QtConcurrent::run or QFuture::then.

    /*
     * Set up the QWidget that we need to monitor.
     */
    auto w = std::make_unique<QLabel>("Working...");
    w->show();
    
    /*
     * Create a QPointer that that we can use to check the validity of 'w'.
     */
    auto qp = QPointer<QWidget>(w.get());
    
    /*
     * We can now bind qp into any lambdas.
     */
    auto f = QtConcurrent::run(
        []
        {
    
            /* Time consuming stuff goes here. */
        })
        .then(
            qApp,
            [qp]
            {
                if (qp) {
    
                    /*
                     * qp reports that 'w' is still valid so do whatever we
                     * need to do with it.
                     */
                    qp.data()->setText("Done");
                } else {
    
                    /*
                     * 'w' is no longer valid.
                     */
                }
            });
    

    [Note: the above is untested as I don't have Qt6 on the box I'm working on right now.]