I recently started investigating Qt for myself and have the following question:
Suppose I have some QTreeWidget* widget
. At some moment I want to add some items to it and this is done via the following call:
QList<QTreeWidgetItem*> items;
// Prepare the items
QTreeWidgetItem* item1 = new QTreeWidgetItem(...);
QTreeWidgetItem* item2 = new QTreeWidgetItem(...);
items.append(item1);
items.append(item2);
widget->addTopLevelItems(items);
So far it looks ok, but I don't actually understand who should control the objects' lifetime. I should explain this with an example:
Let's say, another function calls widget->clear();
. I don't know what happens beneath this call but I do think that memory allocated for item1
and item2
doesn't get disposed here, because their ownage wasn't actually transfered. And, bang, we have a memory leak.
The question is the following - does Qt
have something to offer for this kind of situation? I could use boost::shared_ptr
or any other smart pointer and write something like
shared_ptr<QTreeWidgetItem> ptr(new QTreeWidgetItem(...));
items.append(ptr.get());
but I don't know if the Qt itself would try to make explicit delete
calls on my pointers (which would be disastrous since I state them as shared_ptr
-managed).
How would you solve this problem? Maybe everything is evident and I miss something really simple?
A quick peek into qtreewidget.cpp shows this:
void QTreeWidget::clear()
{
Q_D(QTreeWidget);
selectionModel()->clear();
d->treeModel()->clear();
}
void QTreeModel::clear()
{
SkipSorting skipSorting(this);
for (int i = 0; i < rootItem->childCount(); ++i) {
QTreeWidgetItem *item = rootItem->children.at(i);
item->par = 0;
item->view = 0;
delete item; // <<----- Aha!
}
rootItem->children.clear();
sortPendingTimer.stop();
reset();
}
So it would appear that your call to widget->addTopLevelItems() does indeed cause the QTreeWidget to take ownership of the QTreeWidgetItems. So you shouldn't delete them yourself, or hold them in a shared_ptr, or you'll end up with a double-delete problem.
Qt has its own smart pointers, take a look at http://doc.qt.io/archives/4.6/qsharedpointer.html . Normally, it is though advisable to use the standard ownership hierarchy of Qt whenever possible. That concept is described here: http://doc.qt.io/archives/4.6/objecttrees.html
For your concrete example, this means that you should pass a pointer to the container (i.e. the QTreeWidget) to the constructor of the child objects. Every QWidget subclass constructor takes a pointer to a QWidget for that purpose. When you pass your child pointer to the container, the container takes over the responsibility to clean up the children. This is how you need to modify your example:
QTreeWidgetItem* item1 = new QTreeWidgetItem(..., widget);
QTreeWidgetItem* item2 = new QTreeWidgetItem(..., widget);
(I don't know what the ... are in your example, but the important thing for Qt memory management is the last argument).
Your example of using a smart pointer
shared_ptr<QTreeWidgetItem> ptr(new QTreeWidgetItem(...));
items.append(ptr.get());
is not a good idea, because you break the golden rule of smart pointers: Never use the raw pointer of a smart pointer managed object directly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With