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(); }
-
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]
-
-
@qcoderpro
Correct. Or to be more precise, in the @mrjj/stack version it will be destructed upon exit from themain()
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 beforemain()
exit, aftermain()
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 thisCMD
, and why is it in "the program's cpp file folder"? Windows assumesCMD.EXE
is the system command line interpreter. If you have created someCMD.EXE
of your own in the current directory or higher on yourPATH
, bad things will happen! If by any chance your Qt program is producing aCMD.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 andcd
ed to your directory.So presumably normally
qmake
directory is not on your defaultPATH
, hence the error message. But the Command Prompt used by Qt (Qt Creator?) is set to add thatqmake
directory to yourPATH
, so it will be found from there. ThenNow 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". -
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?
-
@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
(anyQWidget
) has to have aQWidget *parent
, not aQObject *parent
. You will not be able to useQApplication *
as the parent....Hence if you were to stick with your original create
QLabel
with noQWidget
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 explicitdelete
. The same will (presumably, unless a Qt expert tells me otherwise) apply if you introduce, say, aQMainWindow
as the top-level window. -
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 mustdelete
it --- which in the case ofsetAttribute(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 callQApplication::exec()
. You couldnew
anddelete
it explicitly if you wish. I have seen debates about whethersetAttribute(Qt::WA_DeleteOnClose)
on your top-level main window (assuming younew
it!) works correctly or not, simplest is to put it on the stack. -
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!