Shall I delete QObject pointers after using them? - c++

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.

Related

Deleting Pointer to widget Qt 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();
}

Qt object management with Qt Plugins

My question is how to do proper object/resource management when working with Qt plugins. Default RAII does not seem to work well with Qt.
In our application we work with modules (Qt plugins) that are dynamically loaded at runtime. When loaded plugins can initialize themselves and as part of this initialization phase they can add their own widgets to the application.
- to the toolbar
- to a side panel
- etc.
Widgets that are added to the main windows have their ownership also transferred.
This all works fine, but now that our application grows more complicated we also need to pay attention to the shutdown phase. Simply unloading the modules will get us into all kinds of trouble. Objects that aren't there or types that are unloaded while their objects are still alive.
To have a reliable shutdown it seems that the only proper way to go is to do reverse initialization. This also means that every module that adds widgets to the mainwindow must remove them as well. Already trying to do this with the first widgets got me into trouble.
Module A registers widget W with the MainWindow. Preferably I would want to return a scoped object removing and deleting the widget when going out of scope. However already it seems that given widget W you cannot remove it simply from the toolbar as it works with actions (and removing the action does not delete the widget! See example below).
Concluding, it seems to me Qt is made in such a way that it gets ownership of everything and you have to rely on Qt to delete it. This does not work well with modules. I'm looking for a solution/best practice here.
Edit:
I added an example where a module adds a custom widget to the toolbar of the MainWindow. My goal is that the module is in charge of when the widget is deleted, for the reasons stated before. The example is to make the question more concrete. It represents the generic problem - ownership of qt objects - that use this pattern in combination with plugins.
example:
executable.cpp
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0) {
ui->setupUi(this);
LoadPlugin();
}
void LoadPlugin() {
m_plugin = new QPluginLoader("module.dll");
m_plugin->load();
IModule* moduleInstance = qobject_cast<IModule*>(m_plugin->instance());
moduleInstance->Initialize(this);
}
void AddToolbarSection(QWidget* widget) {
/** ownership is transferred here to Qt */
mainToolBar->insertWidget(pWidget);
}
void RemoveToolbarSection(){
/** How to get the widget deleted? */
}
/** this is called before the destructor */
void UnloadPlugin() {
moduleInstance->Shutdown();
m_plugin->unload();
}
~MainWindow() {
/** deletion of toolbar sections must already been done here
as the modules are already unloaded. Otherwise access violations occur
because specific type information is not accessible anymore.
*/
}
private:
Ui::MainWindow *ui;
QPluginLoader* m_plugin;
IModule* m_moduleInstance;
};
module.cpp
class EXPORT_MODULE IModule : public QObject
{
Q_OBJECT
Q_PLUGIN_METADATA(IID IModuleIID)
Q_INTERFACES(IModule)
public:
IModule() {
}
void Initialize(QMainWindow* window) {
/** QMyToolbarSectionWidget is a custom widget defined in this module (module.dll)
it has a specific destructor and triggers all kinds application
specific cleanup */
m_toolbarSection = new QMyToolbarSectionWidget();
window->AddToolbarSection(m_toolbarSection);
}
void Shutdown() {
window->RemoveToolbarSection(m_toolbarSection);
}
private:
QWidget* m_toolbarSection;
};
That's a bit difficult to answer since it depends on your architecture.
In general Qt's idea of cleanup is tied to the parent pointer. i.e
QObject *root;
QObject *leaf = new QObject();
leaf->setParent(root);
root->deleteLater();
QPluginLoader will even cleanup your root component on unload, so in theory, any tree below your plugin is cleared. Simply make sure that everything you return from your root is a QObject parented to your root. If it's not a QObject, wrap it in QObject.
class MyExtension : public QWidget {
QAction *myAction;
MyExtension() : QWidget() {
myAction = new QAction(this);
}
QAction *getAction() {
return myAction
}
}
from your question i understand you might also be working like this:
class MyExtension : public QObject {
MyWindow * myWindow;
QAction * myAction;
MyExtension() : QObject() {
myWindow = new MyWindow(this);
myAction = new QAction(this);
}
void addToMainThing(TheMainThing *tmt) {
tmt->addWidget(myAction);
}
}
same thing. simply always make sure your QObject is parented to something that is parented to your plugin root.
Cross posting this question on the Qt forum got me the following answer.
Even though Qt takes ownership of QWidgets/QObjects that are added to the Ui, it is still possible to delete them from the client side. Qts resource management system is built in such a way that it will know when a QObject gets deleted and it will handle this deletion by updating the UI as well as removing internal references to it. See the link for more details.

How to remove widgets from layout in Qt

I have a piece of code which does this: a method named prepareUI makes the UI ready to be able to load search results that are fed into it. A method named onClear that is called when the results that are already showing needs to be cleared. And a method named populateSearchResults that takes the search data and loads the UI with it. The container that holds the data is a publicly available pointer, since it is needed to clear the results from onClear:
void MyClass::prepareSearchUI() {
//there may be many search results, hence need a scroll view to hold them
fResultsViewBox = new QScrollArea(this);
fResultsViewBox->setGeometry(28,169,224,232);
fSearchResultsLayout = new QGridLayout();
}
void MyClass::onClear() {
//I have tried this, this causes the problem, even though it clears the data correctly
delete fSearchResultContainer;
//tried this, does nothing
QLayoutItem *child;
while ((child = fSearchResultsLayout->takeAt(0)) != 0) {
...
delete child;
}
}
void MyClass::populateWithSearchesults(std::vector<std::string> &aSearchItems) {
fSearchResultContainer = new QWidget();
fSearchResultContainer->setLayout(fSearchResultsLayout);
for (int rowNum = 0; rowNum < aSearchItems.size(); rowNum++) {
QHBoxLayout *row = new QHBoxLayout();
//populate the row with some widgets, all allocated through 'new', without specifying any parent, like
QPushButton *loc = new QPushButton("Foo");
row->addWidget(loc);
fSearchResultsLayout->addLayout(row, rowNum, 0,1,2);
}
fResultsViewBox->setWidget(fSearchResultContainer);
}
Problem is, when I call onClear which internally calls delete, it does remove all the results that were showing. But after that, if I call populateWithSearchesults again, my app crashes, and the stack trace shows this method as where it crashed.
How do I fix this problem?
It seems that you have some misconceptions about ownership. A QLayout takes ownership of any item that is added to it: http://doc.qt.io/qt-5/qlayout.html#addItem
That means the QLayout is responsible for deleting these items. If you delete them then the QLayout will also try to delete them and then you get the crash you're seeing now.
QLayout doesn't have good functionality for deleting contents and re-adding them (for example removeWidget probably doesn't work as you would hope.) But there's a reason for this.
QLayout is not intended to be used as a list view.
What you do want is a, wait for it, QListView. Which will even handle the scroll functionality for you, and make adding and removing elements a possibility.
Actually you can solve this issue easily, even if you are using QGridLayout or any other Layouts :
subLayout->removeWidget(m_visibleCheckBox);//removes and then it causes some zigzag drawing at (0,0)
m_visibleCheckBox->setVisible(false);//asks to redraw the component internally
setLayout(subLayout);//for safety as we may use that layout again and again
If you just use the first line it will cause this :

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.

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