c++qtqfutureqfuturewatcher

Free memory using QFuture on cancel thread


I am writing a program that uses QtConcurrent to start threads. In my case, I use it to render a QGraphicsView when I use the mouse scroll.

I am starting the threads using the following code:

if (future.isRunning()) {
    future.cancel();
}

future = QtConcurrent::run(this,&AeVectorLayer::render, renderparams, pos);
watcher.setFuture(future);

When the thread is finished I catch the signal finished with a QfutureWatcher.

This is my render function:

QList<AeGraphicsItem*> AeVectorLayer::render(Ae::renderParams renderparams, int pos)
{
    AeVectorHandler *coso = new AeVectorHandler();
    coso->openDataset(AeLayer::absoluteFilePath);
    coso->setTransformCoordinates(myEPSG);
    QList<AeGraphicsItem*> bla = coso->getItems(renderparams.sceneRect.x(), 
    renderparams.sceneRect.y(), renderparams.sceneRect.width(), 
    renderparams.sceneRect.height(), renderparams.zoom, color, this);
    for (int i = 0; i < bla.size(); i++)
        bla.at(i)->setZValue((qreal)pos);
    delete coso;
    return bla;
}

As you can see, I have a QList<QGraphicsItem*> in my render function. How can I destroy this list when the future is cancelled? I undestand that in my code I am redefining the future variable but I do not know how to avoid it.


Solution

  • Stop trying to manually manage memory and instead use a smart pointer that fits your use case. Because you use move-unaware QFuture, you will need an std::shared_ptr. Once the QFuture/QFutureWatchers go out of scope, and you hold no more shared_ptr instances, the resource will be deleted. So in your case your render function should return a QList<std::shared_ptr<AeGraphicsItem>>. Be careful when you transfer ownership from the shared_ptrs to e.g. a QGraphicsScene: you must release from the shared_ptr on ownership transfer.

    Note that your isRunning check followed by cancel is fundamentally flawed: the future could be running when you call isRunning but be finished by the time you call cancel. If you want to cancel it, just call cancel. Also note that you cannot meaningfully cancel QFutures returned by QtConcurrent::run so what you're doing is very very wrong in and of itself.