Qt QListWidget addItem memory leak - c++

I have a QComboBox_1 with items added (both icon and text). Then i added item to the QListWidget_1 as below from a QPushButton_1 clicked(). The QListWidget forcing to add a QListWidgetItem as a pointer value.
void MainWindow::on_QPushButton_1_clicked(){
int intSelected = ui->QComboBox_1->currentIndex();
QListWidgetItem *Itm = new QListWidgetItem(ui->QComboBox_1->itemIcon(intSelected), ui->QComboBox_1->itemText(intSelected));
ui->QListWidget_1->addItem(Itm);}
And it is working fine. But i didn't delete the pointer variable "*Itm" in any of the code (MainWindow unload or close). This will create memory leak?
I am a beginner to Qt and C++
Thanks in advance.

No it will not. Technically it's not entirely obvious from the manual, though one definitely can suppose that.
Additionally, in the source of QListWidget.cpp you can see that items are stored inside internal QListModel class which handles deletion of them automatically in its destructor and in other cases when they are removed.

Related

QAbstractItemModel::removeRows does it cause memory leaks?

Suppose I have some code like this:
QListWidgetItem *pItem = new QListWidgetItem(...);
insertItem(i, pItem);
.....
then:
removeRows(..)
If I don't delete the pointer pItem, will it cause memory leak?
From Qt documentation:
If you need to insert a new item into the list at a particular position, then it should be constructed without a parent widget. The insertItem() function should then be used to place it within the list. The list widget will take ownership of the item.
So there is no memory leak.

valgrind issue with QDialog specified with qt designer

I'm developing a simple prototype with qt creator.
I have used designer in order to design my windows.
Say us that main window has a menu with an option called "Suspend". When this option is selected, it is called the method MainWindow::on_actionSuspend_triggered() whose simplified implementation could be resumed as follows:
void MainWindow::on_actionSuspend_triggered()
{
SuspendDialog suspend_dialog(this);
suspend_dialog.setModal(true);
auto status = suspend_dialog.exec();
return;
}
The SuspendDialog was specified with designer, it is derived from QDialog class and it is very simple (three push buttons a combo box and a spin box. This class does not allocate memory.
Now, when I run valgrind inside qtcreator for checking memory usage I get two issues of type Mismatched free() / delete / delete []. Some bizarrus is that the two issues refers the same line, which is at the end of destructor of SuspendDialog whose implementation is:
SuspendDialog::~SuspendDialog()
{
delete ui;
}
And that was automatically generated by qt designer.
My question is: is this a false positive of valgrind or am I doing some wrong?
Thanks in advance
By doing the below you are asking for trouble:
SuspendDialog suspend_dialog(this); // wrong! do not pass 'this' here
Passing pointer to 'this' in Qt implies that you pass the parent responsible for release of that widget. Or, the release will happen twice: first when the object on stack getting destroyed and next when the parent object getting destroyed.
If you execute the dialog with exec() you can still allocate the dialog widget on stack but do not pass this to it:
SuspendDialog suspend_dialog;
//
suspend_dialog.exec(); // exec() only
Or you can allocate the dialog widget in the heap and then you can pass this to it:
SuspendDialog* pSuspendDialog = new SuspendDialog(this);
//
pSuspendDialog->exec(); // or maybe show() depending on task

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 :

Replace QWidget with a new QWidget

This questions to me reeks of maybe a lack of understanding of C++, as the possibilities I've considered for my problem all seem to make no sense on why this could be occuring. Feedback appreciated.
I'm using the form designer to create a form class with a table in it. I'm trying to replace the table with another table generated in a helper class. I'm only doing this so I can (hopefully) maintain the nice grid layout I've designed, and through pointer manipulation, get the replacement I desire. Here's some code snippets from the table form constructor and relevant calls :
//tableData is defined in the header file as a QTableWidget*
tableData = this->findChild<QTableWidget *>("tableData");
....
setup();
void setup(){
tableData = Utilities::createTable(this->file, tableDelim);
//createTable returns QTableWidget*
... other assignments, and label text updates, which seem to all work
}
My understanding is that tableData is a pointer, and if printed, will give the address of the QTableWidget from the layout. So then if I create a QTableWidget* and then assign tableData to that, tableData should now point to the new widget. Instead, I see only a blank screen.
I tried checking what the tableData pointer is before I assign it to the new QTableWidget*, and after. The second pointer shown is what is generated by createTable() :
QTableWidget(0x101272d40, name = "tableData") QTableWidget(0x10127b3b0, name = "test_sample2.nuc.stats")
QTableWidget(0x10127b3b0, name = "test_sample2.nuc.stats") QTableWidget(0x10127b3b0, name = "test_sample2.nuc.stats")
It seems the pointer is being reassigned, but the table drawn isn't the right one.
What gives?
My understanding is that you want to design the table layout in designer but fill in the data from an external source.
I would suggest, to just use the QTableWidget that is created in setupUi() and modify Utilities::createTable() such that it becomes Utilities::populateTable(QTableWidget & table, <all the other parameters you need>). (Or use QTableWidget * if you prefer - however I like putting the non-zero assertion responsibility on the caller...)
Apart from that, I agree with Sebastian Lange.
You are right with your assumption. You do set a variable to be a pointer to a object and next you set the variable to be a pointer to another object. You never change any objects, just your variable which is not used to display anything.
You would need to do something like:
//tableData is defined in the header file as a QTableWidget*
tableData = this->findChild<QTableWidget *>("tableData");
parentLayout = tableData->parent()->layout(); //Get the parent widget to add another table.
parentLayout->removeWidget(tableData);
delete tableData;
parentLayout->addWidget(createTable());
You need to use pTheContainerOfTheOriginalTableWidget->addWidget(tableData); See here: http://qt-project.org/forums/viewthread/16547
Be sure you remove the original tableWidget so you don't have two (I assume you don't want two).
If I understand you correctly we have such situation.
call of setupUi (which generated by qt tootls),
there there is something like this(pseudo code):
oldTablePtr = new QTableWidget(parent);
someLayout->addWidget(oldTablePtr);
So parent and layout hold value of oldTablePtr.
And if you set variable oldTablePtr nothing changed.
parent send QPaintEvent to oldTablePtr.
So you need call delete oldTablePtr, that remove this widget from list of childs of parent, and move newTablePtr to the same layout.
There's no need to replace it in code, you can do it in Qt Designer. Just place QTableWidget on form, then rightclick it and choose Promote widget in menu, then you will need just enter your classname.
Currently I don't have Qt Designer near me, so edits will be appreciated.

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.