0

I have a QTreeView served by a QAbstractItemModel subclass which is built over a custom tree data model. The data model is defined like this:

struct InventoryNode
{
    // ctors, operator definitions
    // ...

    InventoryItem inventoryItem;         // node data
    QList<InventoryNode> children;       // child nodes
    InventoryNode *parent = nullptr;     // parent pointer
};

class InventoryModel : public QAbstractItemModel
{
    Q_OBJECT

public:
    struct InventoryNode;
    QList<InventoryNode> _nodes;             // root nodes

    // required model methods
    // ...
}

Everything is working perfectly, I can add, edit, move and remove rows. Now, if I try to use a QVector instead of QList, the model works as intended when initially populating it with the data, but when I try to add a new row, I experience weird behavior: the row is being added to the model and shown in the view normally, but when I try to expand\collapse neighbouring nodes, the program crashes. I have located the source of the crash, the findRow method, which is used in the required QAbstractItemModel's parent method:

QModelIndex InventoryModel::parent(const QModelIndex &index) const
{
    if (!index.isValid()) {
        return QModelIndex();
    }

    InventoryNode *currentNode = static_cast<InventoryNode *>(index.internalPointer());

    InventoryNode* parentNode = currentNode->parent;
    if (parentNode != nullptr) {
        return createIndex(findRow(parentNode), BranchColumn, parentNode);
    }
    else {
        return QModelIndex();
    }
}

int InventoryModel::findRow(const InventoryNode *targetNode) const
{
    const InventoryNodeList searchList = targetNode->parent != nullptr ? targetNode->siblings() : _nodes;
//    return searchList.indexOf(*targetNode);
    InventoryNodeList::const_iterator position = std::find(searchList.begin(), searchList.end(), *targetNode);
//    Q_ASSERT(position != searchList.end());
    return std::distance(searchList.begin(), position);
}

When I try to expand\collapse a node, searchList.indexOf(*targetNode); crashes the program without any feedback. I wanted to dig deeper and rewrote the search to get some more info about what's happenening and apparently Q_ASSERT(position != searchList.end()); this condition fails.

Now, I've read some info about differences between QVector and QList, including this very helpful discussion. I do understand the main differences between both and get the felling that the main cause is some quirk in the memory management, but I still have hard time figuring out why this happens.

Can someone please explain?

Community
  • 1
  • 1
Kef
  • 410
  • 3
  • 18
  • there should'n be any difference, because in the code you show us no memory allocation or deletion. You are using same for vector and list interface and iterators. For me there is just one strange thing `QList _nodes; ` not list of pointers, but in `findRow()` you are using `std::find(searchList.begin(), searchList.end(), *targetNode);` what if the `short if` statement returns you `_nodes` ? hmm) – Amir Rasulov Apr 20 '17 at 14:51
  • That's exactly why I'm bothered, there should not be any difference, since the behaviour and API of both is the same, but the program crashes as soon as I use `QVector` instead of `QList`. As for pointers, I need to use a pointer to the node to be able to cast it from `index`'s `void*` `internalPointer`. `_nodes` `if` branch will process the tree root =) – Kef Apr 20 '17 at 15:04

0 Answers0