I'm subclassing QAbstractItemModel
to display items in a QTreeView
, and within this subclass (projectModel
), I have a function to delete the currently-selected index in the tree view. Component
is the class used to represent all the members of the model:
void
projectModel::deleteComponent()
{
QModelIndex child_index = _treeview->selectionModel()->currentIndex();
Component* child = static_cast<Component*>(child_index.internalPointer());
Component* parent = child->Parent();
QModelIndex parent_index = createIndex(parent->row(), 0, parent);
int row = child->row();
beginRemoveRows(parent_index, row, row);
parent->delete_child(child);
endRemoveRows();
}
The parent and child indicies and raw pointers are good just before the call to beginRemoveRows
; debugger shows that they point to the correct item and its parent. However, the program crashes after calling beginRemoveRows
. Specifically, it crashes in projectModel::parent()
:
QModelIndex
projectModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
Component* item = getItem(index); //Fails to cast index internal pointer to a valid Component*
Component* parentItem = item->Parent();
if (parentItem == _rootnode)
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
When I break on the crash and examine the debugger output, it shows that the variable item
in the parent()
function is garbage. Somehow it looks like my QModelIndex
gets corrupted between the call to deleteComponent
and the call to parent
. Is there anything blatantly wrong with what I'm doing, or is the problem perhaps more subtle?
This is fully expected.
Non-persistent indices are valid until you change the structure of the model. A structural change is any change that is signaled other than by emitting dataChanged
.
Structural changes must be considered barriers to index lifetime: you must discard any non-persistent indices held from before a structural change.
Depending on where deleteComponent
is called, likely what happens is that the caller holds some indices, the deleteComponent
invalidates them all, and you're in undefined behavior territory from there onwards.
You need to use persistent indices if you want them to stay valid over structural changes, and even then they'll only be valid if the given item still exists. If you're using your own model, you need to explicitly support persistent indices, and the users of your model must use them.
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