3

I have a Pointer to a Object that i pass to a lambda function. Because the lambda function is called 1 second after the initial method call, the object is sometimes not valid any more, leading to a segmentation fault.

How can I verify that the item is still valid within the lambda function before using it?

This is how my method using the lambda function looks like:

void myTab::myMethod(QStandardItem *item)
{
    QColor blue(0, 0, 128, 20); 
    QBrush brush(blue);
    item->setBackground(brush);

    //Restore background after 1000ms
    QTimer::singleShot(1000, [item, this]() mutable {
        item->setBackground(Qt::transparent);     //<-need some advice here
    });
}
Sean
  • 60,939
  • 11
  • 97
  • 136
user3482407
  • 319
  • 3
  • 18
  • 1
    What is the point of `mutable` and why is `this` captured? – James Adkison May 12 '16 at 14:17
  • Possible duplicate of [C/C++ Checking for NULL pointer](http://stackoverflow.com/questions/3825668/c-c-checking-for-null-pointer) – Zafi May 12 '16 at 14:21
  • @Alex -- don't think that is the right dup -- the problem is not null, but pointing to an free memory – Soren May 12 '16 at 14:23
  • Isn't his question how to check whether the pointer is valid i.e. whether it's not a null pointer? – Zafi May 12 '16 at 15:07
  • Nvm, I misread the question. – Zafi May 12 '16 at 15:07
  • It all boils down to not passing pointers around in C++. Stop passing RAW pointers outside of internal interfaces. Use automatic objects to control lifespans not guess work. – Martin York May 12 '16 at 15:17

2 Answers2

9

How can I verify that the item is still valid within the lambda function before using it?

The easiest approach would be to have item be a shared_ptr<QStandardItem> that your lambda just gets a copy of. This guarantees the the item will live long enough:

void myTab::myMethod(std::shared_ptr<QStandardItem> item)
{
    QColor blue(0, 0, 128, 20); 
    QBrush brush(blue);
    item->setBackground(brush);

    //Restore background after 1000ms
    QTimer::singleShot(1000, [item]{
        item->setBackground(Qt::transparent);
    });
}

Otherwise, you can't really tell from a pointer if it points to an object that is still valid or not. Or other weirdness like the object was deleted and a new one happens to be allocated at the same memory and now you have a bug where some random item is becoming transparent occasionally. Better to sidestep all of those problems.


Potentially better as Loki suggests would be to store a weak_ptr to the item. If the item is dead before we can set it to transparent, that's fine - we just don't set it to transparent. If we don't actually need to extend its lifetime, just don't:

QTimer::singleShot(1000, [weak_item = std::weak_ptr<QStandardItem>(item)]{
    if (auto item = weak_item.lock()) {
        item->setBackground(Qt::transparent);
    }
});
Community
  • 1
  • 1
Barry
  • 286,269
  • 29
  • 621
  • 977
  • 1
    Better option would be for the lambda to get a std::weak_ptr. Then when the code decides the object is no longer needed it does not live longer than required. The timer can check it is valid before using. – Martin York May 12 '16 at 15:15
  • @LokiAstari I like it. – Barry May 12 '16 at 15:28
  • 1
    The fact that `QStandardItem` is a Qt object could be problematic. As in, there is a chance that the `QStandardItem` is already owned a `QStandardItemModel` which may preclude the use of `std::shared_ptr`. However, I don't think anyone knows these details except the OP. – James Adkison May 12 '16 at 18:11
  • @James Don't know anything about Qt. This is just a generic answer for this sort of problem - there may be a Qt-specific way of checking item existence for all I know. – Barry May 12 '16 at 18:26
  • @Barry I understand and it's not a critique on your answer. I just thought it may be useful for others to know that more information is required before it could be said this will work for the OP or any Qt users dealing with a similar problem. – James Adkison May 12 '16 at 18:47
0

No suggestion seemed to work for me. I tried std::shared_ptr, std::weak_ptr and QSharedPointer. Seems like the model the item is added to somehow removes the item anyway?! However, I ended up using a QStack where I pushed all the item pointers on the stack and once restored or removed the Items were poped off the stack. Since the time is always the same, this approach works perfekt for me, altough is is not very well implemented.

user3482407
  • 319
  • 3
  • 18