Qt World Summit: Submit your Presentation

endRemoveRows() and QML ListView deleteLater() synchronization

  • Hello,
    I've stumbled on curious problem. If I deleteLater() object after caling endRemoveRows(). ListView delegates will not get destroyed in time and every binding to the deleted item will results in a lot of TypeError: Cannot read property 'foo' of null

    Here's an example:
    Let's preted that I have defined C++ Item

    class MyItem : public QObject {
    Q_PROPERTY(QString foo READ foo WRITE setFoo NOTIFY fooChanged)

    And I put these items into a QAbstractListModel

    class MyModel : public QAbstractListModel {
    QHash<int, QByteArray> Model::roleNames() const {
        QHash<int, QByteArray> roles;
        roles[Qt::UserRole] = "object";
        return roles;

    where data() with ObjectRole returns *Item
    and I remove these Items like this

    MyModel::removeItem(MyÏtem* item) {
        if (item && m_items.contains(item)) {
            int index = m_items.indexOf(item);
            beginRemoveRows(QModelIndex(), index, index);

    Finally my QML for this model can be simple as this

    ListView {
        delegate: Text {
            property MyItem myItem: model.object
            text: myItem.foo

    After removing item from model, Qt will fire that TypeError. but item will be destroyed both from C++ and from QML. But if I stall deleteLater like this QTimer::singleShot(10, [=]{ item->deleteLater();}); then everything will works okay. Also I have to use this nesting because my Items are quite big and I connect their signals and pass their pointer to a lot of places. I also have to delete object, because the item holds a lot of memory that I need to be freed.
    It's obvious the C++ deletes object much faster than QML destroys ListView delegate. The question is, how can my C++ Model know when it is safe to deleteLater()?

  • Had the same problem.

    Fixed it by not binding the object referenced by the role to a property and using the property but using the role name directly to acces the model item.

    Instead of

    property MyItem myItem: model.object
    text: myItem.foo


    text: model.object.foo