Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

A little memory leak in a simple Qt program



  • Hi,
    In the following simple code we have a little memory leak until the program terminates which is related to label because anywhere we have "new" we must also have "delete" later on. But the memory leak here is harmless. How to avoid it, please? Where is the appropriate place to put "delete" on?

    #include <QApplication>
    #include <QLabel>
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
        QLabel *label = new QLabel("Hello Qt!");
        label->show();
        return app.exec();
    }
    

  • Lifetime Qt Champion

    Hi
    In Qt you normally put labels in a window/form and it will deleted when finished.
    please read about this system here
    https://doc.qt.io/qt-5/objecttrees.html
    So often for Qt Widgets, you do not need to call delete your self.

    This case does leak however since label has no parent and hence becomes a window.

    Since its main, you can fix this with

    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
        QLabel label("Hello Qt!");
        label.show();
        return app.exec();
    }
    

    and it will auto clean up.

    [Edit: fixed typo SGaist]


  • Lifetime Qt Champion

    Hi,

    Beside @mrjj's suggestion, nothing stops you from doing the cleanup:

    int status = app.exec();
    delete label;
    return status;
    


  • So in the @mrjj version, the widget (label) is created on the stack, and it will be destructed at the program's termination. But in the @SGaist version, the widget is created on the heap and will get deleted before the program terminates. True?



  • @qcoderpro
    Correct. Or to be more precise, in the @mrjj/stack version it will be destructed upon exit from the main() function. Which is not quite the same thing as "program's termination", it happens a little bit before the program actually terminates/exits. This may be relevant if you are checking for "memory leak", e.g. with a tool, depending on whether it checks before main() exit, after main() exit, or just before process exit.



  • One more question. When CMD, is in the program's cpp file folder and I type in "qmake -project", it writes:
    'qmake' is not recognized as an internal or external command,
    operable program or batch file
    .
    I've previously set the address to mingw on system variables: C:\Qt\5.14.2\mingw73_64\bin



  • @qcoderpro
    What is this CMD, and why is it in "the program's cpp file folder"? Windows assumes CMD.EXE is the system command line interpreter. If you have created some CMD.EXE of your own in the current directory or higher on your PATH, bad things will happen! If by any chance your Qt program is producing a CMD.EXE you need to change that immediately!



  • @JonB
    No I meant the built-in Windows CMD. and by going into it I meant usig that CMD and typing the path to program's directory so that the control is there. I don't know why it didn't work.

    This time I used the command prompt offered by Qt and it recognized the command the created the project file and makefiles.
    Now neither "make", nor the name of the project work as command there to run the program!



  • @qcoderpro
    Oh, so you mean you opened a Command Prompt window and cded to your directory.

    So presumably normally qmake directory is not on your default PATH, hence the error message. But the Command Prompt used by Qt (Qt Creator?) is set to add that qmake directory to your PATH, so it will be found from there. Then

    Now neither "make", nor the name of the project work as command there to run the program!

    So look at what PATH actually is set to (and what the current directory is) when using "the command prompt offered by Qt".


  • Lifetime Qt Champion

    Hi
    after you open the cmd
    call
    "C:\Qt\5.14.1\msvc2017_64\bin\qtenv2.bat"
    or
    "C:\Qt\5.14.1\mingw73_64\bin\qtenv2.bat"
    adjust path to math your compiler / installation
    then its setup.



  • Thanks.
    About the first post. Why have we a little leak there, please? Is it because the label won't get deleted until the program terminates? When was is it supposed to be deleted to avoid leaking?

    And if we want to have a proper code for that example based on Qt standards, we need to firstly have a parent, like a QMainWindow or QWidget or even the QApplication itself, and then set it as the parent to the label. True?


  • Lifetime Qt Champion

    @qcoderpro said in A little memory leak in a simple Qt program:

    Thanks.
    About the first post. Why have we a little leak there, please? Is it because the label won't get deleted until the program terminates? When was is it supposed to be deleted to avoid leaking?

    When you use new on a Qt type, and do not give it a parent, you must manually delete it.
    so in fist code, its been newed so it won't be cleanup as such when the program exits. ( well it will but on OS level)

    And if we want to have a proper code for that example based on Qt standards, we need to firstly have a parent, like a QMainWindow or QWidget or even the QApplication itself, and then set it as the parent to the label. True?

    True. the parent must exist to assign it but in many cases,
    the labels are put inside a form or similar so it makes sense.



  • @qcoderpro said in A little memory leak in a simple Qt program:

    And if we want to have a proper code for that example based on Qt standards, we need to firstly have a parent, like a QMainWindow or QWidget or even the QApplication itself, and then set it as the parent to the label. True?

    QLabel (any QWidget) has to have a QWidget *parent, not a QObject *parent. You will not be able to use QApplication * as the parent....

    Hence if you were to stick with your original create QLabel with no QWidget available to be its parent, to have it deleted you would need to use one of the two approaches: @mrjj's make it a stack variable or @SGaist's do an explicit delete. The same will (presumably, unless a Qt expert tells me otherwise) apply if you introduce, say, a QMainWindow as the top-level window.



  • @JonB

    (any QWidget) has to have a QWidget *parent

    Does it mean that every widget's parent must only be a QWidegt or any other widget which has inherited QWidget?



  • @qcoderpro

    Does it mean that every widget's parent must only be a QWidegt or any other widget which has inherited QWidget?

    Yes, or nullptr, which means it has no parent. Usually a top-level widget (a window) does not have a parent.
    If you must create a parentless widget on the heap and hope it be automatically deleted when it is closed, you can use:

    setAttribute(Qt::WA_DeleteOnClose)
    


  • @Bonnie
    cool hint! :)

    That actually raised this question in my mind. We say widgets built on the heap (using new) must be either explicitly deleted using the "delete" keyword or child of a parent. Assume we've 10 widgets created on the heap. Then they're all children of a top-level widget, for example, a QMainWindow. Actually we should be certain that QMainWindow is deleted, since it comprises many heap widgets, before the program terminates. One solution is the one you said. Another solution is to firstly create the top-level widget on the stack (although its children are created on the heap). Do you know of a third solution?



  • @qcoderpro
    We usually just create the top-level widget on the stack or delete it manually.
    If you do want to create the widget on the heap and do not want to delete it manually, you need Qt to delete it for you.
    For example, what the "Qt::WA_DeleteOnClose" attribute do is, as the doc says, "Makes Qt delete this widget when the widget has accepted the close event".
    So Qt delete it for you after it is closed.
    But if the window is created but never shows, then it won't be deleted (because it never closes).
    Another solution I can think of would be using QSharedPointer, it will "delete the pointer it is holding when it goes out of scope".



  • @qcoderpro
    How many different solutions do you want? :)

    There are only really two: if you new it you must delete it --- which in the case of setAttribute(Qt::WA_DeleteOnClose) is done for you by the Qt framework when the window is closed --- or if you put it on the stack it gets deleted by the run-time code when it goes out of scope.

    In the case of your one QMainWindow it is usual to allocate this on the stack in the method where you call QApplication::exec(). You could new and delete it explicitly if you wish. I have seen debates about whether setAttribute(Qt::WA_DeleteOnClose) on your top-level main window (assuming you new it!) works correctly or not, simplest is to put it on the stack.



  • @JonB

    So the best habit is to create the top level widget on the stack and parent the children, all, to it, regardless of them being created on heap or stack as well. So this way there is almost no class which needs to implement the destructor!

    One other thing I didn't understand well I think is the termination time of a top-level widget, actually our program, the time when it goes out of scope and Qt deletes it from the stack. This will be done when we close the program, not? But "setAttribute(Qt::WA_DeleteOnClose)" seemingly works the same way too!


Log in to reply