Consider the following snippet code:
1: QPushButton *p_Button = new QPushButton(this);
2: QPushButton myButton(this);
Line 1: this is referred to QWidget, so p_Button is child of QWidget in my example: when QWidget dies (goes out the scope??) his destructor deletes p_Button from the heap and calls the destructor of p_Button.
Line 2: Same as Line 1, but does the destructor of QWidget delete myButton since its child is also myButton?
Please correct me if I stated something wrong and reply to my questions.
Yes and yes. If a QObject is not created by new, it must be destroyed before its parent. Otherwise, the parent will delete the child and the program may crash.
Qt has some good documentation on object trees and ownership that explains this.
Related
I am new with Qt and i am very confused about how widgets are deleted. I was reading a video and i wanted to show up a QProgressbar while the video frames are being read and then remove this QProgressbar when the video is loaded.
I have done it with 2 different ways:
Using Pointers
QWidget* wd = new QWidget();
QProgressBar* pB = new QProgressBar(wd);
QLabel* label = new QLabel(wd);
//setting geometry and updating the label and progressbar
wd->deleteLater();
wd->hide();
this code is written inside a class and i was assuming when the destructor of this class is called, the widget will be deleted with all of it's children but that didn't happen and everytime i run this function again a new widget is created without hiding or deleting the previous one (NOTE: i have tried to delete the label and progressbar from the widget assuming that they will disappear from inside the widget but this didn't happen "delete(pB);")
Using Objects
QWidget wd;
QProgressBar pB(&wd);
QLabel label(wd);
//setting geometry and updating the label and progressbar
wd.deleteLater();
wd.hide();
When i have run the same code but using objects instead of pointers , it has run exactly as i have wanted and everytime i run the function, the old widget is destroyed and a new one is created.
NOTE: -Also when i close the main window, in case of pointers, the widget wd still exists and the program doesn't terminate until i close them manually
- In case of Objects, when i close the main window everything is closed and the program is terminated correctly.
I need someone to explain me why is this happening and how if i am having a vector of pointers to widgets to delete all pointers inside that vector without any memory leakage
In typical C++ the rule would be "write one delete for every new". An even more advanced rule would be "probably don't write new or delete and bury that in the RIAA pattern instead". Qt changes the rule in this regard because it introduces its own memory management paradigm. It's based on parent/child relationships. QWidgets that are newed can be given a parentWidget(). When the parentWidget() is destroyed, all of its children will be destroyed. Hence, in Qt it is common practice to allocate objects on the stack with new, give them a parent, and never delete the memory yourself. The rules get more complicated with QLayout and such becomes sometimes Qt objects take ownership of widgets and sometimes they don't.
In your case, you probably don't need the deleteLater call. That posts a message to Qt's internal event loop. The message says, "Delete me when you get a chance!" If you want the class to manage wd just give it a parent of this. Then the whole parent/child tree will get deleted when your class is deleted.
It's all really simple. QObject-derived classes are just like any other C++ class, with one exception: if a QObject has children, it will delete the children in its destructor. Keep in mind that QWidget is-a QObject. If you have an instance allocated usingnew`, you must delete it, or ensure that something (a smart pointer!) does.
Of course, attempting to delete something you didn't dynamically allocate is an error, thus:
If you don't dynamically allocate a QObject, don't deleteLater or delete it.
If you don't dynamically allocate a QObject's children, make sure they are gone before the object gets destructed.
Also, don't hide widgets you're about to destruct. It's pointless.
To manage widget lifetime yourself, you should use smart pointers:
class MyClass {
QScopedPointer<QWidget> m_widget;
public:
MyClass() :
widget{new QWidget};
{
auto wd = m_widget->data();
auto pb = new QProgressBar{wd};
auto label = new QLabel{wd};
}
};
When you destroy MyClass, the scoped pointer's destructor will delete the widget instance, and its QObject::~QObject destructor will delete its children.
Of course, none of this is necessary: you should simply create the objects as direct members of the class:
class MyClass {
// The order of declaration has meaning! Parents must precede children.
QWidget m_widget;
QProgressBar m_bar{&m_widget};
QLabel m_label{&m_widget};
public:
MyClass() {}
};
Normally you'd be using a layout for the child widgets:
class MyClass {
QWidget m_widget;
QVBoxLayout m_layout{&m_widget};
QProgressBar m_bar;
QLabel m_label;
public:
MyClass() {
m_layout.addWidget(&m_bar);
m_layout.addWidget(&m_label);
}
};
When you add widgets to the layout, it reparents them to the widget the layout has been set on.
The compiler-generated destructor looks as below. You can't write such code, since the compiler-generated code will double-destroy the already destroyed objects, but let's pretend you could.
MyClass::~MyClass() {
m_label.~QLabel();
m_bar.~QProgressBar();
m_layout.~QVBoxLayout();
// At this point m_widget has no children and its `~QObject()` destructor
// won't perform any child deletions.
m_widget.~QWidget();
}
Is there a order to declare widgets in Qt5(perhaps 4 too) ?
Consider the following pieces of code:
(just the a piece of the header to help me explain)
class ConfigDialog : public QDialog
{
Q_OBJECT
QGroupBox userAuthBox;
QGridLayout userAuthLayout;
QVBoxLayout dialogLayout;
QLabel userLabel;
QLabel passLabel;
QLineEdit userEdit;
QLineEdit passEdit;
};
this works as expected but just changing to (reordering declarations):
class ConfigDialog : public QDialog
{
Q_OBJECT
QLabel userLabel;
QLabel passLabel;
QLineEdit userEdit;
QLineEdit passEdit;
QGroupBox userAuthBox;
QGridLayout userAuthLayout;
QVBoxLayout dialogLayout;
};
this works also, but when the ConfigDialog goes out of scope happen a segfault.
I've saw this on other scenarios too, but always changing the order fix this.
My guess would be: you make your QGroupBox a parent of some of the other widgets.
Qt has a concept of parent-child relationship between QObjects. The parent is responsible for deleting its children when it itself is destroyed; it is assumed that those children were allocated on the heap with new.
Further, data members of a C++ class are constructed in the order they are listed in the class, and are destroyed in the reverse order.
Let's say userAuthBox is made a parent of userLabel (via setParent call, in your case executed by addWidget). In the first case, userLabel is destroyed first, and notifies its parent of this fact, whereupon userAuthBox removes it from its list of child widgets, and doesn't attempt to delete it.
In the second case, userAuthBox is destroyed first, and uses delete on its pointer to userLabel. But of course userLabel was not in fact allocated with new. The program then exhibits undefined behavior.
TL;DR: Yes! The order of declarations has a strictly defined meaning in C++. A random order will not work, as you've happened to notice.
You're not showing all the code. What is important is that one of the widgets is a child of the group box. Suppose you had:
class ConfigDialog : public QDialog
{
// WRONG
Q_OBJECT
QLabel userLabel;
QGroupBox userAuthBox;
QGridLayout userAuthLayout;
QVBoxLayout dialogLayout;
public:
ConfigDialog(QWidget * parent = 0) :
QDialog(parent),
dialogLayout(this),
userAuthLayout(&userAuthBox) {
// Here userLabel is parent-less.
Q_ASSERT(! userLabel.parent());
userAuthLayout.addWidget(&userLabel, 0, 0);
// But here userLabel is a child of userAuthBox
Q_ASSERT(userLabel.parent() == &userAuthBox);
}
};
The default destructor will invoke the destructors in the following order - it literally is as if you wrote the following valid C++ code in the destructor.
dialogLayout.~QVBoxLayout() - OK. At this point, the dialog is simply layout-less. All the child widgets remain.
userAuthLayout.~QGridLayout() - OK. At this point, the group box is simply layout-less. All the child widgets remain.
userAuthBox.~QGroupBox() - oops. Since userLabel is a child of this object, the nested userAuthox.~QObject call will execute the eqivalent of the following line:
delete &userLabel;
Since userLabel was never allocated using new, you get undefined behavior and, in your case, a crash.
Instead, you should:
Declare child widgets and QObjects after their parents.
Use C++11 value initialization if possible, or initializer lists in the constructor to indicate to the maintainer that there is a dependency between the children and the parents.
See this answer for details and a C++11 and C++98 solution that will force the mistakes to be caught by all popular modern static C++ code analyzers. Use them if you can.
For example:
QFile* file = new QFile...
If there is no delete file is it memory leak? I ask because I'm new in Qt and reviewing some code I've found this so I wonder if that is sane for Qt classes or not?
Using QFile, there are usually no reason to make it dynamic, but yes -> delete should be here, or else it will leak.
in Qt there are only one exception from mandatory rule "for each new there should be delete".
If you are creating widget with parent like this:
QWidget* w = new QWidget();
QWidget* w2 = new QWidget(w);
Once you you delete w - all it's children (w2 in our case) also will be deleted. This shortens code, but this is only an exception. Rest of stuff - should be deleted.
Edited: Of course, you can use QScopedPointer, or usual std::unique_ptr.
The rule is simple. If QObject has a parent then it will be deleted by parent. If not, you should delete it yourself.
I use this code:
MyDialog *md = new MyDialog();
md -> show();
to open a dialog window in Qt. Will md be deleted automatically when the dialog window is closed or do I need to run delete md when the window is finished?
In your little piece of code you need to delete it, because it doesn't have a parent, if you set a parent, the parent will delete it's children and you only need to delete the "main-window" (the window that doesn't have a parent).
Also for QWidget derived classes you can use the: Qt::WA_DeleteOnClose flag and then the memory will be deallocated when the widget closes, see the documentation here
Then code will become:
MyDialog *md = new MyDialog();
md->setAttribute(Qt::WA_DeleteOnClose);
md->show();
Yes. Unless you pass this while this is a QWidget or any other QWidget:
MyDialog *md = new MyDialog(this);
md->show();
you need to:
delete md;
at some point in order to release its memory. Also you need to make sure in this case that the object tree is well linked. What you can also do is call setAttribute(Qt::WA_DeleteOnClose); on md so that when you close the dialog, its memory will also be released as Zlatomir said. However if you need md to live after it was closed setAttribute(Qt::WA_DeleteOnClose); is not an option. This is also dangerous and could lead to access violation/segmentation fault if you are not careful.
In the constructor of MainWindow i have a chunk of code:
QMenu * filemenu = this->menuBar()->addMenu(tr("File"));
QAction * openButton = new QAction(tr("Open"), this);
connect(openButton, SIGNAL(triggered()), this, SLOT(input()));
filemenu->addAction(openButton);
Everything seemed to be fine until I ran a memory check. Valgrind seems to be saying that there is a memory leak here. Shouldn’t the QMenu be automatically deleted right before MainWindow is deleted? I tried remembering the pointer to filemenu and deleting it manually in the MainWindow destructor but it didn't change anything. Does anyone have an idea what am I doing wrong?
Shouldn’t the QMenu be automatically deleted right before MainWindow is deleted?
You could connect a slot to the destroyed() signal of your QMenu instance (filemenu) and print out something there with qDebug(). If that gets printed for the mainwindow destruction that means the destructor is called, i.e. deleted.
...
connect(myMenuPointer, SIGNAL(destroyed()), receiverPointer, SLOT(test()));
...
MyClass::test()
{
qDebug() << "My menu deleted automatically";
}
Sometimes, there is memory leak detected in a Qt application by valgrind if something underneath leaks the memory like glibc and so on. It might be the case, but the answer to your question is that QMenu will be automatically deleted.