views:

233

answers:

3

Hello!

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?

+3  A: 

Qt has its own smart pointers, take a look at http://doc.qt.nokia.com/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.nokia.com/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.

Daniel M.
@Daniel M. So if I *"bind"* my child items to the parent widget as you wrote, can I be sure that a `clear()` call, for instance, would dispose that memory?
HardCoder1986
Yes, you can. As long as you're using Qt's memory management, Qt makes sure that all objects are deleted when their parent is deleted (so Qt operates strictly tree-based regarding parent-child memory management.
Daniel M.
If you use the append() or addWidget() or similar functions, you don't explicitely set the parent in the constructor, although it never hurts.
rubenvb
A: 

Many Qt class instances can be constructed with a parent QObject*. This parent controls the life time of the constructed child. See if QTreeWidgetItem can be linked to a parent widget, which seems so, reading Qt docs:

Items are usually constructed with a parent that is either a QTreeWidget (for top-level items) or a QTreeWidgetItem (for items on lower levels of the tree).

Hernán
+4  A: 

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.

Jeremy Friesner