Are destructors necessary in QDialogs? - c++

I am following Qt examples (like TabDialog) and I notice that all the UI items are created as pointers - yet I see no delete and no destructor.
Is that right ? Will that not lead to memory leak ?
I am trying to add destructors
~TabDialog()
{
delete tabWidget;
delete buttonBox;
}
and on caller
TabDialog *tabDialog = new TabDialog();
tabDialog->setAttribute(Qt::WA_DeleteOnClose);
tabDialog->exec();
But the program crashes when I close the dialog.
Are the destructors, and delete all pointer items, unnecessary or am I doing it wrong ?

I think that you are confused because of these lines:
tabWidget = new QTabWidget;//and so on
You don't see explicit parent (like new QTabWidget(this);), but it is not necessary here. Take a look here:
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(tabWidget);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setLayout will reparent your QVBoxLayout and QVBoxLayout will reparent all widgets inside it, so now your widgets has a parent and they will be destroyed after your dialog.
As doc said:
When you use a layout, you do not need to pass a parent when
constructing the child widgets. The layout will automatically reparent
the widgets (using QWidget::setParent()) so that they are children of
the widget on which the layout is installed.
Note: Widgets in a layout are children of the widget on which the
layout is installed, not of the layout itself. Widgets can only have
other widgets as parent, not layouts.

I'm sorry, but this just doesn't reproduce. The test case is below. You'd probably need to add some extra code to make it reproduce.
Qt's memory management will take care of everything, since all of the widgets end up having parents. Namely:
Tabs are parented as soon as they are passed to addTab.
tabWidget and buttonBox are parented as soon as they are added to the layout.
Since you delete the tabWidget and buttonBox before Qt attempts to delete them, everything is fine. As soon as you delete them, QObject's memory management is informed and they are removed from the TabDialog's child list. I've made this point explicit in the destructor code.
The meaning of Q_ASSERT is: "At this point during runtime, the following must be true". If we're wrong, the debug build will abort. Since it doesn't, the assertions are correct. Thus, before delete tabWidget, the dialog has both QTabWidget and QDialogButtonBox children. After delete tabWidget, the dialog should not have any QTabWidget children anymore. And so on.
#include <QApplication>
#include <QDialog>
#include <QTabWidget>
#include <QDialogButtonBox>
#include <QVBoxLayout>
class TabDialog : public QDialog
{
QTabWidget *tabWidget;
QDialogButtonBox *buttonBox;
public:
TabDialog() :
tabWidget(new QTabWidget),
buttonBox(new QDialogButtonBox(QDialogButtonBox::Ok |
QDialogButtonBox::Cancel))
{
tabWidget->addTab(new QWidget, tr("General"));
tabWidget->addTab(new QWidget, tr("Permissions"));
tabWidget->addTab(new QWidget, tr("Applications"));
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(tabWidget);
layout->addWidget(buttonBox);
setLayout(layout);
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
}
~TabDialog() {
Q_ASSERT(findChild<QTabWidget*>());
Q_ASSERT(findChild<QDialogButtonBox*>());
delete tabWidget;
Q_ASSERT(! findChild<QTabWidget*>());
Q_ASSERT(findChild<QDialogButtonBox*>());
delete buttonBox;
Q_ASSERT(! findChild<QTabWidget*>());
Q_ASSERT(! findChild<QDialogButtonBox*>());
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TabDialog *tabDialog = new TabDialog();
tabDialog->setAttribute(Qt::WA_DeleteOnClose);
tabDialog->exec();
return 0;
}
The only way it'd crash is if you tried the following:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TabDialog *tabDialog = new TabDialog();
tabDialog->setAttribute(Qt::WA_DeleteOnClose);
tabDialog->exec();
// At this point `tabDialog` is a dangling pointer.
delete tabDialog; // crash
return 0;
}
Unfortunately, Qt examples are a case of pointless premature pessimization. Qt's classes utilize the PIMPL idiom extensively. Thus the size of, say a QTabWidget is not much larger than that of QObject (48 vs. 16 bytes on my 64 bit platform). By allocating the fixed members of your class on the heap, you're performing two heap allocations: a small one for the QObject-derived class, and then another one for its PIMPL. You're doubling the number of allocations for no good reason.
Here's how to avoid this pessimization:
#include <QApplication>
#include <QDialog>
#include <QTabWidget>
#include <QDialogButtonBox>
#include <QVBoxLayout>
class TabDialog : public QDialog
{
QVBoxLayout m_layout;
QTabWidget m_tabWidget;
QDialogButtonBox m_buttonBox;
QWidget m_generalTab, m_permissionsTab, m_applicationsTab;
public:
TabDialog() :
m_layout(this),
m_buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel)
{
m_tabWidget.addTab(&m_generalTab, tr("General"));
m_tabWidget.addTab(&m_permissionsTab, tr("Permissions"));
m_tabWidget.addTab(&m_applicationsTab, tr("Applications"));
m_layout.addWidget(&m_tabWidget);
m_layout.addWidget(&m_buttonBox);
connect(&m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(&m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
auto tabDialog = new TabDialog();
tabDialog->setAttribute(Qt::WA_DeleteOnClose);
tabDialog->show(); // NOT tabDialog->exec()!!
return app.exec();
}
The less explicit heap allocations, the better. This way you can't even be tempted to delete anything in the destructor, since there are no pointers involved. The compiler generates necessary destructor calls for you automatically.
Furthermore, if you're showing only one window in main, there's no point to explicit heap allocation either:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
TabDialog tabDialog;
tabDialog.show();
return app.exec();
}

Memory handling on Qt
Qt handles the widgets as a tree, every widget has a parent and every parent has
the obligation to free the children memory, if a widget has no parent you should delete it manually with the operator delete.

Related

QMainWindow with member QWidget and QLayout crashes on exit, how to fix that?

The following is a single-file QWidget program.
//main.cpp
#include <QApplication>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QLabel>
class MainWindow:public QMainWindow{
QLabel lb;
QWidget wgt;
QVBoxLayout lout{&wgt};
public:
MainWindow(){
lout.addWidget(&lb);//line A
setCentralWidget(&wgt);
}
};
int main(int argc, char *argv[]){
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
The program crashes on exit. The function-call trace on crash is
system calls
QObjectPrivate::deleteChildren()
QWidget::~QWidget()
QMainWindow::~MainWindow
main
If line A is removed then there is no crash.
I want to figure out what causes the crash, and how to use member QWidget and QLayout without having a crash. Thanks in advance.
While the problem is due to an attempt to free memory that wasn't allocated on the heap I don't think the QMainWindow destructor or a 'double-delete' is the culprit (as suggested elsewhere).
As well as deleting its children the QObject destructor will also remove itself from any parent's object hierarchy. In the code shown wgt is a data member of MainWindow meaning wgt's dtor will be invoked before that of the MainWindow instance. Hence, by the time ~MainWindow is invoked wgt is no longer a child and no attempt will be made to free it at that point. So that's not the issue.
Instead the real problem is the order in which the data members lb, lout and wgt are declared in the MainWindow class...
class MainWindow: public QMainWindow {
QLabel lb;
QWidget wgt;
QVBoxLayout lout{&wgt};
The widget hierarchy is...
wgt
\_lb
and the implicit construction order...
lb
lout
wgt
meaning the order in which the dtors is invoked is...
wgt
lout
lb
Thus, when wgt destructor is called lb is still a child and wgt will attempt to free it. That's the cause of the problem in this particular case. While it can be solved by allocating the various QObjects on the heap, an alternative solution would be to simply re-order the member declarations within MainWindow to ensure the correct order of construction and destruction...
class MainWindow: public QMainWindow {
QWidget wgt;
QVBoxLayout lout{&wgt};
QLabel lb;

Is there a right or wrong for ownership in Qt

I would like to write "modern C++" Qt applications, meaning with as much RAII as possible. Therefore I ask myself if it is safe to use automatic allocation when possible like this:
#include <QApplication>
#include <QtWidgets>
int main(int argc, char **argv) {
QApplication app{argc, argv};
QWidget window{};
window.setWindowTitle("Der eine Knopf");
QPushButton button{"Ende"};
QObject::connect( &button, SIGNAL(clicked()), &app, SLOT(quit()));
QVBoxLayout layout{};
layout.addWidget(&button);
window.setLayout(&layout);
window.show();
return app.exec();
}
Whereas the original tutorial code had a lot of pointers and heap:
#include <QApplication>
#include <QtWidgets>
int main(int argc, char **argv) {
QApplication app{argc, argv};
QWidget window{};
window.setWindowTitle("Hallo Qt");
QPushButton button = new QPushButton("Ende");
QObject::connect( button, SIGNAL(clicked()),
&app, SLOT(quit()));
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(button);
window.setLayout(layout);
window.show();
return app.exec();
}
I am aware of Qt's ownership concept of QObjects in general. So I assume the second example is correct. I assume that setLayout and addWidget also change the ownership and thus no explicit delete is needed for me as a client.
And assuming that I wonder -- why does my first example work then? If those methods acquire ownership, will they not delete their newly acquired children in the end? If they do, will my program not crash because the objects are removed twice? (The program does not crash, I would have mentioned that. But that could be by accident, right?)
I am now so much confused who owns whom and how does it work that I do not know how it could. The one rule I heard was "Qt will take care of that" -- but "of what"? And of what not?
Well, obviously I am new to Qt and what I would like is some insights into the QObjects constructor and destructor counts. Or messages for each construction and/or destruction. Is there such a facility in Qt?
If you take a look at object trees and ownership, when you use automatic allocation you have to watch out for the order of creation. The destructors of local objects are called in reverse order of their constructors.
So in your example:
int main(int argc, char **argv) {
QApplication app{argc, argv};
QWidget window{};
window.setWindowTitle("Der eine Knopf");
QPushButton button{"Ende"};
QObject::connect( &button, SIGNAL(clicked()), &app, SLOT(quit()));
QVBoxLayout layout{};
layout.addWidget(&button);
window.setLayout(&layout);
window.show();
return app.exec();
}
Here you create a QWidget object called window. Then you create a QPushButton. You set a layout to your widget, and add the button to that layout. The layout will automatically set window as the parent of button. But when you exit your application and the scope ends, button will be destroyed first. And upon its destruction it will be removed from window's list of children. So it won't be destroyed twice.
However if you create button before window, window will be destroyed before button, and it will also destroy all of it's children. Which means it will also call the destructor of button. After this the destructor of button will be called again as it went out of scope. So here you would have a big problem.

Why are QWidgets accessed by pointers?

I am new to Qt5 and I am learning QWidgets to develop an application.
I've noticed in many examples, QWidgets are almost always accessed by pointer. For example:
#include <QApplication>
#include <QWidget>
#include <QFrame>
#include <QGridLayout>
class Cursors : public QWidget {
public:
Cursors(QWidget *parent = 0);
};
Cursors::Cursors(QWidget *parent)
: QWidget(parent) {
QFrame *frame1 = new QFrame(this);
frame1->setFrameStyle(QFrame::Box);
frame1->setCursor(Qt::SizeAllCursor);
QFrame *frame2 = new QFrame(this);
frame2->setFrameStyle(QFrame::Box);
frame2->setCursor(Qt::WaitCursor);
QFrame *frame3 = new QFrame(this);
frame3->setFrameStyle(QFrame::Box);
frame3->setCursor(Qt::PointingHandCursor);
QGridLayout *grid = new QGridLayout(this);
grid->addWidget(frame1, 0, 0);
grid->addWidget(frame2, 0, 1);
grid->addWidget(frame3, 0, 2);
setLayout(grid);
}
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Cursors window;
window.resize(350, 150);
window.setWindowTitle("Cursors");
window.show();
return app.exec();
}
This is taken from the tutorial: http://zetcode.com/gui/qt5/firstprograms/
Yet, on the same page, I see that we can access the QWidget base class by its object itself:
#include <QApplication>
#include <QWidget>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget window;
window.resize(250, 150);
window.setWindowTitle("Simple example");
window.show();
return app.exec();
}
Why is it necessary to access all QWidget derived classes by their pointer? Why isn't it necessary to access QWidget itself by its pointer?
It's all about object's lifetime and shared ownership. If you create an object on stack in function, it will be destroyed when scope ends.
Why isn't it necessary to access QWidget by pointer in your example? Just because when main() 'ends', your program is finished, and widget may be destroyed.
Why is it necessary to access QWidget's children by pointer? Because if you want to ask QWidget to give you access to it's child, it can't give you a value, because it would be just a copy of an object. Moreover, if you pass a large object by value to QWidget, it needs to copy your object.
This is not specific to QWidgets: it is so for every QObjects (Qt fundamental base class, from which everything else is derived).
It is the consequence of a design choice of the Qt framework. Quoting Qt documentation:
QObject has neither a copy constructor nor an assignment operator.
This is by design.
[...]
The main consequence is that you should use
pointers to QObject (or to your QObject subclass) where you might
otherwise be tempted to use your QObject subclass as a value. For
example, without a copy constructor, you can't use a subclass of
QObject as the value to be stored in one of the container classes. You
must store pointers.
Source:
http://doc.qt.io/qt-5.5/qobject.html#no-copy-constructor
The rationale for this choice is explained here:
http://doc.qt.io/qt-5.5/object.html#identity-vs-value
QClasses are larger in size and you don't want to fill up your stack memory by instantiating them in stack memory.
When you instantiate derived class objects it also runs constructor of a base class ( derived class + base class ) memory is required,
On the other hand QWidget only inherits QObject and QPaintDevice as you can see here
So it will be less overhead to create QWidget object on stack memory.
You must be very careful when you are using heap memory, read the answers on memory management
You can study the difference between stack and heap from here

Qt : how to implement QDialog StatusBar

I have QDialog that is heavily designed with QDesigner , I saw on the web that I could add QStatusBar with code like this :
#include <QDialog>
#include <QStatusBar>
#include <QLayout>
#include <QApplication>
#include <QTextEdit>
#include <QStatusTipEvent>
class Dialog : public QDialog {
public:
Dialog() : QDialog(){
QLayout *l = new QVBoxLayout(this);
QTextEdit *te = new QTextEdit;
te->setStatusTip("XXX");
l->addWidget(te);
bar = new QStatusBar;
l->addWidget(bar);
l->setMargin(0);
l->setSpacing(0);
}
private:
QStatusBar *bar;
protected:
bool event(QEvent *e){
if(e->type()==QEvent::StatusTip){
QStatusTipEvent *ev = (QStatusTipEvent*)e;
bar->showMessage(ev->tip());
return true;
}
return QDialog::event(e);
}
};
int main(int argc, char **argv){
QApplication app(argc, argv);
Dialog dlg;
return dlg.exec();
}
Its not even working in my case .. maybe the QDialog is already have few layets that holds widget.
My question is can I some how use palceholder in the QDesigner or somehow promote widget that place hold the QStatusbar class? I don’t know …
What can I do in such case? can I implement new QStatusbar?
Thanks
I presume when you say it doesn't work, that you are not seeing the status bar when you run.
I don't see any way to do this wholly in the designer. The designer certainly resists the idea of promoting something to a QStatusBar. I suppose you could fool the designer by subclassing QStatusBar, and then promoting a QWidget to your subclass.
But I don't think we need to go that route just yet. I think with a few tweaks to the code you have above should help.
In the designer, add a layout, it doesn't matter what kind, at the bottom of your dialog. I called mine 'StatusBarLayout'. You can see the layout (the red box that's squished at the bottom). I removed the bottom margin in the dialog so that the status bar is flush at the bottom.
Now remove everything in the above code about layout l, and just do this:
bar = new QStatusBar(this);
pUI->StatusBarLayout->addWidget(bar);
pUI->textEdit->setStatusTip("XXX");
The textEdit was something added in the designer. Now when you run it you should see this:
I hope that helps
Edit:
You can also set the Status Tips for various widgets in the designer too, so there is no need to do that in the code unless you want to.
Try adding a QStatusBar like this:
QDialog dialog;
QLayout* layoutWidget = new QVBoxLayout(&dialog);
layoutWidget ->addWidget(new QTextEdit);
QStatusBar* statusBar = new QStatusBar;
layoutWidget ->addWidget(statusBar );

qt example from the book

I have this snippet of the code:
#include <QApplication>
#include <QFont>
#include <QPushButton>
#include <QWidget>
class MyWidget : public QWidget
{
public:
MyWidget(QWidget *parent = 0);
};
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
setFixedSize(200, 120);
QPushButton *quit = new QPushButton(tr("Quit"), this);
quit->setGeometry(62, 40, 75, 30);
quit->setFont(QFont("Times", 18, QFont::Bold));
connect(quit, SIGNAL(clicked()), qApp, SLOT(quit()));
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MyWidget widget;
widget.show();
return app.exec();
}
can somebody please explain what exactly is going on in this line
MyWidget(QWidget *parent = 0);
a little bit difficult understand what is this parent, thanks in advance
That is an argument to the constructor with a default argument (NULL since NULL is defined as 0 as per the c++ standard). Default meaning passing no parameter is the same as passing NULL.
Since Qt's widgets are arranged in a hierarchal system (parent -> child relationships) parent is the widget which is the "owner" or "container" of the current one (NULL means no parent aka a root widget of sorts). For GUI items a widget will often have the widget it is contained in as its parent.
This is advantageous since when a parent is deleted, it will delete any children is has automatically removing the need for much of the memory management that comes with c++.
The parent argument is for giving parents to new widgets. When given, it is useful for Qt to manage the object tree. (To automatically delete child objects.) It also has the concrete visible effect of "attaching" a new widget to another widget (ie, the parent). In your code however, the parent argument is not ever given, causing the widget to appear as a top level window and not to be deleted by Qt automatically. (It would not require deletion by Qt anyway in that code though.)
Its a 0 pointer (think NULL without the type), or in Qt terms, "no parent".