Deleting Pointer to widget Qt C++ - c++

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();
}

Related

Shall I delete QObject pointers after using them?

Shall I delete QObject pointers after using them in Qt 5.7.0?
For example, I have got the code:
std::string login;
std::string password;
if (serviceId == 11) {
QObject* loginField = this->parent()->findChild<QObject*>("wifiLogintxt1");
QObject* passwordField = this->parent()->findChild<QObject*>("wifiPasswordtxt1");
login = loginField->property("text").toString().toStdString();
password = passwordField->property("text").toString().toStdString();
} else {
QObject* loginField = this->parent()->findChild<QObject*>("inputField1");
login = loginField->property("text").toString().toStdString();
}
Will the code lead to a memory leak, because we don't delete QObject pointers?
No, You shouldn't delete these objects, they are managed by their parent QObjects, see QObject trees and ownership:
When using findChild, you are getting a pointer to the same object managed by this parent.
So, loginField, passwordField are deleted when their parent widget is deleted (this instance in your case). If you delete them, they will disappear from the GUI. You have to keep them until the parent widget decides they are no longer needed (that is the time when it is destructed):
You can also delete child objects yourself, and they will remove themselves from their parents. For example, when the user removes a toolbar it may lead to the application deleting one of its QToolBar objects, in which case the tool bar's QMainWindow parent would detect the change and reconfigure its screen space accordingly.

There's a widget declaration order to follow?

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.

QGraphicsView shows nothing

I'm still learning Qt, I did a little project in Qt, i create a simple ui using qt ui designer, and using QGraphicsView to display a image loaded by QFileDialog, but when I added loaded image file to QgraphicsScene, the image is not displayed in the graphicview. The graphicView stay blank, please help me, thanks !
Project2::Project2(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui = new Ui::Project2Class;
ui->setupUi(this);
this->scene = new QGraphicsScene;
this->scene->setSceneRect(0, 0, 649, 459);
connect(ui->mapLoaderButton, SIGNAL(clicked()), this, SLOT(GetfilePath()));
ui->graphicsView->setScene(this->scene);
}
void Project2::GetfilePath()
{
QString filePath = QFileDialog::getOpenFileName(this, tr("Select file"), "", tr("Files (*.jpg*)"));
if (filePath.isNull() == false)
{
QImage image(filePath);
QSize size = image.size();
ui->graphicsView->scene()->addItem(&QGraphicsPixmapItem(QPixmap::fromImage(image)));
ui->graphicsView->scene()->update();
ui->graphicsView->viewport()->update();
}}
QGraphicsScene, and most of Qt, takes ownership of the variable. The variable should be dynamically allocated.
Variables created on the stack won't work, because their lifetimes are too short and the QObject will later try and delete them.
You need to create your QGraphicsPixmapItem with 'new'.
ui->graphicsView->scene()->addItem(new QGraphicsPixmapItem(QPixmap::fromImage(image)));
Everything that inherits from QObject can own (and be owned by) other QObject classes. When a QObject is destroyed, it calls 'delete' on all its children. QObject classes want to 'own' their children. By 'own' I mean control the lifetimes of.
In your case, you were creating the QObject (QGraphicsPixmapItem) on the stack. It's lifetime is then controlled by the stack (but the QObject thinks it's controlling it), and the stack will delete it by the time it reaches the semi-colon of that 'addItem()' function-call.
As a general C++ rule-of-thumb, if a function is asking for a pointer, don't give it a temporary (unnamed) object.
As a general Qt rule-of-thumb, if a function is asking for a pointer, don't even given it a named local-variable - most want a dynamically allocated variable, so look the function up on the documentation and see if it mentions 'taking ownership'. If so, 'new' it and let Qt later 'delete' it.

Deleting widget that is in layout

What will happen if we will run delete widget for widget that is in layout? If this case was written in documentation, please give me the link (I didn't find).
Code example:
QLabel *l1 = new QLabel("1st");
QLabel *l2 = new QLabel("2nd");
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(l1);
layout->addWidget(l2);
QWidget *mainWidget = new QWidget;
mainWidget->setLayout(layout);
mainWidget->show();
delete l1;
l2->deleteLater();
Can things that will happen be different for l1 and l2?
I believe what you are doing is almost same, though neither would properly remove from layout the way you should be doing it. They are still being left as bad references in the layout (if I remember correctly)
The first one simply deletes the item now. The second will delete it once the control returns back to the event loop. But really, the way people usually remove items from a layout is to take them from the layout (giving it a chance to adjust itself), then delete the item and its widget (if you want).
QLayoutItem *child;
while ((child = layout->takeAt(0)) != 0) {
delete child->widget();
delete child;
}
Again, the deleting of the widget (child->widget()) is only needed if you want to destroy the widget that was added, in addition to the layout item that was holding it.
QLayout's listen for events of type ChildRemoved and remove the items
accordingly. Simply deleting the widget is safe.
by #FrankOsterfeld here.
dont use delete l1 on Qobjects that has active slots connected to them, you will run into a crash.
Use:
l1->hide();
l1->deleteLater();
It works fine for me
Generally, I don't like to delete Qt widgets, rather remove them from the appropriate layout. (Qt will delete its own widgets if you set the Delete on close window attribute. ) The difference between calling delete and delete later is that delete is the normal C++ delete operation that will call the destructor and free the memory associated with the object.
The deleteLater() method, as discussed in the Qt documentation deletes the object when the event loop is entered.

MFC: Deleting dynamically created CWnd objects

Lets say in a dialog, we dynamically create a variable number of CWnds... like creating a and registering a CButton every time the user does something/
Some pseudo-code...
class CMyDlg : public CDialog
{
vector<CWnd *> windows;
void onClick()
{
CButton *pButton = new CButton(...);
//do other stuff like position it here
windows.push_back(pButton);
}
}
Do I need to explicitly delete them or will MFC do it? If I have to, would it be in the destructor as normal, or are there any special things to avoid breaking MFC... making sure I don't delete the objects while the HWNDs are still in use for example?
CButton *pButton = new CButton(...);
These are C++ objects, which needs to be deleted explicitly. (Where as Main frame windows and Views are self destructed).
You can refer the detailed answer ( by me) Destroying Window Objects