0
#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include <QPushButton>
#include <QDebug>
#include <QThread>

class Worker : public QObject
{
    Q_OBJECT

public:
    Worker()
    {
        qDebug() << "ctor Worker";
    }

    ~Worker()
    {
        qDebug() << "dtor Worker";
    }

    void doWork()
    {
        qDebug() << "working";
    }

signals:
    void resultReady();

};

class Controller : public QObject
{
    Q_OBJECT

    QThread thread;

public:
    Controller()
    {
        Worker* worker = new Worker;
        worker->moveToThread(&thread);

        connect(this, &Controller::start, worker, &Worker::doWork);
        connect(worker, &Worker::resultReady, this, &Controller::handleResults);

        thread.start();
    }

    ~Controller()
    {
        thread.quit();
        thread.wait();
    }

public slots:
    void handleResults()
    {
        qDebug() << "results done.";
    }

signals:
    void start();

};

class Widget : public QWidget
{
    Q_OBJECT

    QHBoxLayout hLayout;
    QPushButton bt;

    Controller& core;

public:
    Widget(Controller& c)
        : QWidget(), core(c)
    {
        setLayout(&hLayout);
        hLayout.addWidget(&bt);

        bt.setText("ok");

        connect(&bt, &QPushButton::clicked, &core, &Controller::start);
    }
};

#include "main.moc"

int main(int argc, char* argv[])
{
    QApplication app(argc, argv);

    Controller core;
    Widget w{core};

    w.resize(400, 300);
    w.show();

    return app.exec();
}

In the above I think we are missing

delete worker

Anyway the program terminates with code 0.

The Worker destructor isn't called, right? Still program terminates with code 0. Is everything fine?

Is there any technique I can use while coding in order to prevent program to return 0 when there is a leak? I guess the answer is smart pointers but Qt connect requires raw pointer?

KcFnMi
  • 5,516
  • 10
  • 62
  • 136
  • No, not everything is fine. You have a memory leak. Unless Qt takes over ownership with move to thread call. – Pepijn Kramer Feb 22 '23 at 08:52
  • 1
    `new Worker`? Who will `delete` this object? In [the Qt thread documentation](https://wiki.qt.io/QThreads_general_usage) notice of the example is using `deleteLater` connected to the `finished` signals. – Some programmer dude Feb 22 '23 at 08:53
  • Yes, according to what I was told, `delete worker` is missing. But how can we investigate this kind of issue. How should I look for memory leaks? When program terminates with non zero code I have a clue something is wrong but otherwise, I have no idea. – KcFnMi Feb 22 '23 at 08:57
  • 1
    Memory leaks aren't run time errors. You cannot detect them with the return code of your program. You should either use a tool that will detect it or review your code to find out all cases when you don't free the allocated memory. – vahancho Feb 22 '23 at 09:01
  • Would appreciate to have some suggestions of tools that will help detecting those leaks? – KcFnMi Feb 22 '23 at 09:12
  • Typically a memory leak is noticed when somebody spots that the process is slowly using more and more memory over time, when it has no reason to. Then you can investigate it either with code review or with specialized tools like Valgrind. – Frodyne Feb 22 '23 at 09:12
  • Isn't Valgrind just for Linux? What about Windows and macOS projects, how people deal with that on those environments? – KcFnMi Feb 22 '23 at 09:14
  • There is Valgrind https://valgrind.org/ and various sanitizers https://github.com/google/sanitizers https://learn.microsoft.com/en-us/cpp/sanitizers/?view=msvc-170 – Frodyne Feb 22 '23 at 09:14
  • I never used Valgrind, may I ask for the steps to go against this specific leak? – KcFnMi Feb 22 '23 at 09:15
  • Also: https://stackoverflow.com/questions/413477/is-there-a-good-valgrind-substitute-for-windows – Frodyne Feb 22 '23 at 09:15
  • why you new something in the constructor instead of using std::shared_ptr or std::unique_ptr – Jesse Feb 22 '23 at 09:51
  • [How to find memory leak in a C++ code/project?](https://stackoverflow.com/q/6261201/) – JaMiT Feb 22 '23 at 10:15
  • @Jesse moveToThread requires a raw pointer. A smart pointer will be gone when it loses the scope. The alternative seems to be member variables? – KcFnMi Feb 22 '23 at 10:43
  • 1
    Detecting whether your destructor was called and having memory leaks are not directly related. When your program terminates, there is no memory leak. The OS will free all memory pages used in your program, regardless of whether that memory was freed (delete []'d) or not. – markus-nm Feb 22 '23 at 14:43
  • And specifically in your case with Qt and QObjects/QThreads, you should not delete the worker object yourself. It is not owned by your thread. Let the worker thread delete this object when the thread finishes. I.e. QObject::connect(mythreadptr, &QThread::finished, myworkerptr, &QObject::deleteLater); – markus-nm Feb 22 '23 at 14:47

0 Answers0