Indeed, QModelIndex should be thought of like an STL iterator. Any code that might modify the structure of the underlying model should be assumed to invalidate that iterator. And calling a function that results in outgoing calls (like a signal emission, or event processing) must be assumed to modify the model structure.
QPMI is the solution to this problem. Why not use that in the case below? Expanding QModelIndex to be more than a short-lived reference to an item in the model would perhaps make some specific use cases easier - but at very high cost (like heap-allocated QVariants). However, the only code that can reliably use anything stored inside the index is the model itself anyway (a view or other generic client code cannot generally assume anything about what internalData() might return). And the model knows when a model index might have been invalidated, and would need to somehow update the payload in constructed QModelIndex instances - what should QModelIndex::internalData() return if the index has been removed from the model? So what do we win? Implementing models that take care of the QPMI updating correctly is not trivial, and the mental model for “finding an item by identity” is not straight forward. In some other model/view frameworks (like React), items have a unique key (often a UUID) that doesn't change when the model's structure changes. In QAIM, this could just be a role value. For most use cases, such a key could then be stored by client (e.g. view) code instead of the index, and while a generic implementation of finding the index for the key would have O(n) complexity (for a flat model), a model can of course implement a faster lookup (using a hash or whatever). This can already be done by anyone right now, just adding a Qt::UserRole to the model to return a key-for-index, and implementing a persistent mapping from key-to-item/index in their model. For lists and tables this is trivial. For trees… well, nothing is trivial for trees, and a unique key in React also is only unique amongst sibling items. The path concept I introduced with QRangeModelAdapter in 6.11 might help, as long as your tree is shaped to only allow children at column 0 items. Qt's views won't be able to use any of this, but that's true for bigger QModelIndex payload as well. Volker > On 2 Jul 2026, at 12:34, Igor Khanin <[email protected]> wrote: > > Hi Bogdan, > > Perhaps I misunderstood, but isn't `QPersistentModelIndex` Qt's current > solution to your motivational example of needing to keep a model index beyond > the current event loop tick? How does it currently fall short? > > My understanding is that `QModelIndex` is intended as a lightweight and cheap > to copy reference into a model as it exists at the moment it was created, > very much akin to a STL iterator. I think that having it hold arbitrary data, > or participate in the ownership of the model data, goes against that. > > Best, > Igor > > On 01/07/2026 16:02, Bogdan Vatra via Development wrote: >> Hello there, >> >> I'd like to propose a new accessor on QModelIndex for Qt 7 and get feedback >> from the list: >> >> QVariant QModelIndex::internalData() const; >> or >> std::any QModelIndex::internalData() const; // as std::any is 1/2 of >> sizeof(QVariant). >> >> Why? >> QModelIndex currently exposes two ways for a model to attach opaque context >> to >> an index: >> >> quintptr QModelIndex::internalId() const; >> void *QModelIndex::internalPointer() const; >> >> Both work well for *static* model content, where the model's backing data >> lives for as long as the model itself. >> They fall short for *dynamic* models, where individual items can be created, >> moved, or destroyed independently of any QModelIndex that currently >> references >> them. >> >> Let me give you an example which will randomly crash a QSortFilterProxyModel: >> >> // main loop has a QAbstractItemModel::dataChanged (or any other QAIM signal >> which will reset the idx internalPointer) event posted, e.g by another thread >> // get an idx >> myView->setCurrentIndex(idx); >> myView->scrollTo(idx); // At this point there is no way to know if idx is >> still valid. It depends on what `myView->setCurrentIndex(idx);` is doing and >> there is no way to know if internalPointer is still valid or not. If inside >> of >> that method QCoreApplication::processEvents is called, myView->scrollTo(idx) >> gets an invalid idx... >> >> How my proposal fixes this problem? >> In a QVariant/std::any we can store a smart pointer and this way the data is >> valid all the time. It can still hold a plain quintptr for models that don't >> need this, so internalId()/internalPointer() could become thin wrappers >> around >> the same underlying storage instead of needing a member variable of their >> own. >> >> >> Cheers, >> BogDan. >> >> P.S. It can not go in Qt6 as it will break the ABI ... >> >> > -- > Development mailing list > [email protected] > https://lists.qt-project.org/listinfo/development -- Development mailing list [email protected] https://lists.qt-project.org/listinfo/development
