Understanding QTimer with a Lambda Call and a Recursive Function

I have the following code:

void class::Testfunc()
{
    QTimer* timer = new QTimer;
    QObject::connect(timer, &QTimer::timeout, [this](){
        emit Log("Time out...");
        TestFunc(serverAddress, requestsFolderPath);
       // deleteLater(); //*** why does this crash if used to replace the connect below?
    });
    connect(timer, &QTimer::timeout, timer, &QTimer::deleteLater);
    timer->setSingleShot(true);
    timer->start(1000);
}

A single shot timer is created with a line connected to the lambda function, which registers the entrance to the lambda function every second (prints text to standard output) and calls the function again.

This works without a problem. However, if I delete the connect call for deleteLater (below the lambda function), but include the deleteLater call in the lambda function, the function will fail. It prints once and right after that, it fails while trying to delete a timer object.

What is the difference between the two calls to deleteLater in this instance and why placing deleteLater in a lambda function causes a problem here, while creating a separate connection works as expected, although both call deleteLater in response to a timeout signal timer?

+4
2

, , , , , , class , QTimer, .

, , deleteLater QTimer instance, .

connect(timer, &QTimer::timeout, timer, &QTimer::deleteLater);

, , , , . , :

QObject::connect(timer, &QTimer::timeout, [this, timer](){
//                                               ^^^^^
    emit Log("Time out...");
    TestFunc(serverAddress, requestsFolderPath);
    timer->deleteLater();
//  ^^^^^^^
});
+8

. Qt . Qt 5.4 backported Qt 5.0-5.3:

// https://github.com/KubaO/stackoverflown/tree/master/questions/qtimer-retrofit-26713879
#include <QtCore>

struct Class : QObject {
   void TestFunc();
   void Log(const char *str) { qDebug() << str; }
};

#if QT_VERSION >= QT_VERSION_CHECK(5,4,0)
namespace compat { using QT_PREPEND_NAMESPACE(QTimer); }
#else
QT_BEGIN_NAMESPACE
Q_CORE_EXPORT void qDeleteInEventHandler(QObject *o);
QT_END_NAMESPACE
namespace compat {
using QT_PREPEND_NAMESPACE(qDeleteInEventHandler);
template <class Fun> struct SingleShotHelper : QObject, Fun {
   QBasicTimer timer;
   template <class F> SingleShotHelper(int msec, QObject *context, F &&fun) :
      QObject(context ? context : QAbstractEventDispatcher::instance()),
      Fun(std::forward<F>(fun)) {
      timer.start(msec, this);
      if (!context)
         connect(qApp, &QCoreApplication::aboutToQuit, this, &QObject::deleteLater);
   }
   void timerEvent(QTimerEvent *ev) override {
      if (ev->timerId() != timer.timerId()) return;
      timer.stop();
      (*this)();
      qDeleteInEventHandler(this);
   }
};
using Q_QTimer = QT_PREPEND_NAMESPACE(QTimer);
class QTimer : public Q_QTimer {
   Q_OBJECT
public:
   QTimer(QObject *parent = {}) : Q_QTimer(parent) {} // C++17: using Q_QTimer::Q_QTimer;
   template <class Fun>
   inline static void singleShot(int msec, QObject *context, Fun &&fun) {
      new SingleShotHelper<Fun>(msec, context, std::forward<Fun>(fun));
   }
}; }
#endif

void Class::TestFunc() {
   compat::QTimer::singleShot(1000, this, [this]{
      emit Log("Timeout...");
      TestFunc();
   });
}
0

All Articles