2

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.

Petar Petrov
  • 702
  • 5
  • 14
Zharios
  • 183
  • 1
  • 18
  • According to the [documentation](http://doc.qt.io/qt-5/qfuture.html#cancel) the `QFuture` returned by `QtConcurrent::run` can *not* be canceled. – G.M. Jul 11 '18 at 11:42
  • @G.M. Yes, i know this. But when you use the cancel() method you can recived a Canceled() event from QFutureWatcher when the thread is finished. My problem is that i lost the reference to the canceled thread and them i can`t recive this event. In this event i could then delete the QList and avoid the memory problem. – Zharios Jul 11 '18 at 11:48
  • You need to provide more information. Who or what is responsible for the ownership of the `AeGraphicsItem *` items in `bla`? Also, why is `coso` allocated on the free store rather than on the stack? – G.M. Jul 11 '18 at 18:04
  • @G.M. `coso` allocated on the free store because is only used to open a shapefile (*.shp) with OGR and get my the list of Geometries of him transformed to a QGraphicsItem – Zharios Jul 11 '18 at 20:12

1 Answers1

1

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.

rubenvb
  • 74,642
  • 33
  • 187
  • 332
  • I try use this but was impossible run well the program. I decided use a class that inherit from QThread and implement my own Cancel() method. Thanks for your help. – Zharios Jul 13 '18 at 12:20