Freeing up memory for global variables
-
Good afternoon everyone, I would like to know if it is customary to delete global variables on the destructor in qt?
For example:
<<<<<<
Global.h
Extern MainWindow *newWindow;
Extern QWidget *newWidget;
Global.cpp
MainWindow *newWindow;
QWidget *newWidget;<<<<<<
MainWindow.h
class MainWindow : public QObject
{
….
MainWindow();
~MainWindow();
};MainWindow.cpp
MainWindow::MainWindow()
{
newWidget = new QWidget;
}MainWindow::~MainWindow()
{
delete newWidget;
newWidget = nullptr;
}<<<<<<<
Int main()
{
QApplication a;
newWindow = new MainWindow;
return a.exec();
}
Is it done the way I wrote above? And how do I clear the memory for newWindow? -
But it depends on what you do with with
newWidget
after you created it vianewWindow = new MainWindow;
inMainWindow::MainWindow()
. Do you really do nothing with it, as you show?It is true that if your code is exactly as you show, nothing more, then, yes, you should
delete newWidget;
inMainWindow::~MainWindow()
. On the other hand, since youdelete newWindow
immediately after creating it and before callinga.exec()
your application has no windows at all.Returning from
a.exec()
does not "clear any memory" or do anything itself.If the intention is to create a main window, show it, run the UI and then exit (e.g. when the user closes the window) then from C++ most people would create the main window on the stack rather than heap/
new
so nodelete
ing:int main() { QApplication a; MainWindow newWindow; newWindow.show(); return a.exec(); }
-
You don't delete the Mainwindow instance anywhere. Don't use global variables - none of them is needed in your example.Or properly clean them up after usage.
-
@DmitryTS
Exactly as @Christian-Ehrlicher says: don't use global variables.But also note that a lot of the time you use Qt Object Trees & Ownership which will mean
QObject
s (which includes allQWidget
s) will do the destruction of all children for you. For example, in your code ifnewWidget
is placed onnewWindow
, e.g. you create it vianewWidget = new QWidget(newWindow)
[new QWidget(this)
if you do it insideMainWindow
class] or you put it on a layout onnewWindow
, then you no longer delete/destroy it,newWindow
will do so. -
@Christian-Ehrlicher Well, to remove mainWindow, I need add : Delete newWindow?
int main()
{
QApplication a;
newWindow = new MainWindow;
Delete newWindow;
return a.exec();
}
and am I removing the QWidget in the MainWindow destructor correctly? -
@DmitryTS said in Freeing up memory for global variables:
and am I removing the QWidget in the MainWindow destructor correctly?
Not if you place the
newWidget = new QWidget;
which you create insideMainWindow::MainWindow()
anywhere on theMainWindow
. Which seems highly likely, unless it is a standalone, top-level widget of its own, which I doubt. -
But it depends on what you do with with
newWidget
after you created it vianewWindow = new MainWindow;
inMainWindow::MainWindow()
. Do you really do nothing with it, as you show?It is true that if your code is exactly as you show, nothing more, then, yes, you should
delete newWidget;
inMainWindow::~MainWindow()
. On the other hand, since youdelete newWindow
immediately after creating it and before callinga.exec()
your application has no windows at all.Returning from
a.exec()
does not "clear any memory" or do anything itself.If the intention is to create a main window, show it, run the UI and then exit (e.g. when the user closes the window) then from C++ most people would create the main window on the stack rather than heap/
new
so nodelete
ing:int main() { QApplication a; MainWindow newWindow; newWindow.show(); return a.exec(); }
-
@DmitryTS
P.S.
Don't forget that you do not have to writereturn a.exec()
as the final line inmain()
. If you have code you want to run before returning frommain()
you can always go e.g.int main() { QApplication a; foo = new Foo; // Foo *foo could be in main() or a global if you really want ... int result = a.exec(); delete foo; return result; }
-
@DmitryTS
In practice, you rarely need to delete top level widgets explicitly.If you have only one window, your app will quit as soon as this window is closed (default behavior of QApplication)
If you have multi doc windows, you can set this proterty:
myWindow->setAttribute(Qt::WA_DeleteOnClose);Et voilà, no more worries with that :)
-
@mpergand said in Freeing up memory for global variables:
If you have only one window, your app will quit as soon as this window is closed (default behavior of QApplication)
Untested, but doesn't
QWidget *widget = new QWidget; return app.exec()
leak thenew
ed widget/window (e.g. for valgrind) if you don'tdelete
or set auto-delete on close on it? -
@JonB said in Freeing up memory for global variables:
Untested, but doesn't QWidget *widget = new QWidget; return app.exec() leak the newed widget/window (e.g. for valgrind) if you don't delete or set auto-delete on close on it?
If nobody deletes it, it is leaked. I would hope that valgrind would catch it (haven't used valgrind on real projects, yet). However, it is really annoying if you close an application and it takes a couple of seconds to actually disappear because it is doing all kinds of clean up. The operating system will reclaim all memory anyway. So, I'm in the camp of "don't clean up after yourself" when closing your application. Not as a hard rule, but certainly as a place for optimization of the user experience.
-
-
@DmitryTS None of these pairs of lines are equivalent. A QScopedPointer deletes the object it points to when it is destroyed.
A raw pointer that is destroyed because it gets out of scope does not trigger the deletion of the objects it points to. You have to explicitly use
delete
on it before. -
@SimonSchroeder , @mpergand
And I am not of the camp who say "don't bother to delete when you are exiting because everything gets destroyed anyway". Thereby hangs the indistinguishability of what are "genuine" leaks in your code versus ones which you choose not to count as leaks because they are "top-level" or "you know about them". It seems to me there are two possible situations:- There is only "one" top-level/global allocated variable: in which case it's one line of code to free it and it won't take any time.
- There are "hundreds" of such, or in some "hierarchy": in which case I revert to if you don't free them you won't be able to see anything left over which are your "genuine" leaks.
We are, of course, all entitled to our styles/opinions. I really don't see how you use valgrind or equivalent properly with your approach. If you really feel it could take too long in production then at least write the disposal code in a
#ifdef
or run-time conditional check which you check during development/analysis and disable for end-user.@DmitryTS
So there you are: you have different opinions. As @SGaist says your examples ofQScopedPointer
are not the same as the non-ones. You can use it if you wish, but my own feeling is while you are learning it does little harm to write explicit code to do the deleting.In itself this has little to do with why you want "global variables" in the very first place.
-
@SGaist Did I understand correctly, that the QWidget object will not be deleted, if there is the following example, and I will first need to explicitly delete it using delete?
int main()
{
QApplication a(…);
QWidget *myWidget = new QWidget;
QScopedPointer <myWidget> pSmart;
return a.exec();
} -
@JonB I fully agree - not cleaning stuff up on exit will only harm memory leak debugging and may also lead to crashes now and then on exit due to wrong order of deletion.
-
@DmitryTS said in Freeing up memory for global variables:
Did I understand correctly
No. You misunderstood what @SGaist wrote.
In that code snippet the QWidget will be deleted because of QScopedPointer. -
@JonB thanks, global var of course it is used , I just took a micro piece, I just want to figure out how they can be cleared, since I cannot change these global variables, they are used in 10,000 lines, and most of all they are used for qml components( calling some additional functions),
in principle, all the work is done on a very old version of qt, and the launch comes from a docker container, where there is not even valgrind :(