首页 > 解决方案 > QLinkedList 中 Qt 迭代器的问题

问题描述

我知道我会被要求提供一个最小的例子,但我不确定是否能想出一个,或者它不会是最小的。但我仍然可以从这次讨论中学到宝贵的知识。

因此,我在 QLinkedList 中组织了一系列给定类的数据项。为用户提供了一个界面,该界面允许浏览该数据并对其进行编辑。特别是,一些可能的编辑操作需要修改 QLinkedList 中的多个条目 - 例如所有后续或所有先前条目。也可以在列表中添加或删除项目,然后进行编辑。

在代码中,我只是让一个迭代器保持最新,它指向链中的当前数据项,称为m_currentItem. 然后我用它来显示当前项目的数据,从当前循环到结尾或开头。我要求这个迭代器在应用程序的整个执行和生命周期内都有效,即使添加或删除项目也是如此。当用户按下“下一个”或“上一个”时,迭代器只是递增或递减。当用户删除列表中的一个项目(最后一个除外)时,迭代器然后指向下一个条目并显示其内容。当用户在列表中添加一个项目时,m_currentItem现在会指向这个新项目。

这就是事情出错的地方:在那些向后或向前的循环上。他们经常(但不总是......)超越结束条件并继续进入未知数据,直到发生重大崩溃。有时它还会循环回到列表中的第一个元素(!!!),然后它对你来说是一个无限循环。

这是取自我的代码的示例,有什么明显错误吗?关于 Qt 迭代器还有什么我应该知道的吗?

编辑 :

刚刚了解了反向迭代器!似乎建议使用它们而不是--标准迭代器上的重载运算符!但是如何制作m_currentItems反向迭代器?

我还阅读了有关隐式共享的信息......我并没有真正做我不认为的那样的事情,但这是否表明我不应该像我一样使用长寿命的迭代器?

include <QLinkedList>

struct Member
{
    int memberID;
}

struct Item
{
    /* A map of members, each mapped to an ID */
    QMap<int, Member> m_members;
    QString name;
}

typedef QLinkedList<Item> LinkedItems;

LinkedItems m_items;
LinkedItems::iterator m_currentItem;

...

if(m_currentItem != m_items.end())
{
    for(LinkedItems::iterator iter = m_currentItem+1; iter != m_items.end(); iter++)
    {
        // Do things on *iter
    }
}

一个更复杂的实现:在每个链接的项目中找到包含数据和 ID 的成员。用户可以在所有先前的项目中传播一个 ID,该 ID 位于他被要求选择的项目之前(该项目本身必须位于当前项目之前)。

例如,如果我们有 ABCDEF 并且用户在 E 上,他可以选择将 E 的成员 ID 传播到 C 和以前的项目(所以 A 和 B 也是 - 但不是 D)。

这是代码。大多数或所有迭代器循环都受到意外行为的影响。

void renameAllPreviousMembers(int memberIDToPropagate)
{
    /* If first item, then there is no previous altogether */
    if(m_currentItem != m_items.begin())
    {
        if(m_currentItem.m_members.contains(memberIDToPropagate) == false)
        {
            QMessageBox::critical(nullptr, tr("Rename members in previous items"),
                                          tr("There is no member with the selected ID in the current item."),
                                          QMessageBox::Ok);
            return;
        }

        bool chose_item;
        LinkedItems::iterator itemIter;
        QStringList previousItems;
        QStringList previousItemsBetterOrder;
        QMap<QString, LinkedItems::iterator> previousItemsMap;

        previousItemsMap.clear();

        /* Find all previous items and store them in a QStringList and a map between those strings and actual items */
        std::cout << "Search previous items : " << std::flush;
        for(itemIter = m_items.begin();
            itemIter != m_currentItem;
            itemIter++)
        {
            /* Possibly add conditions on some items that we do not want to apply values to. */
            std::cout << itemIter->name << ", " << std::flush;
            previousItems << itemIter->name;
            previousItemsMap.insert(itemIter->name, itemIter);
        }
        std::cout << "finished." << std::endl << std::flush;

        QStringList::reverse_iterator riter;

        for(riter = previousItems.rbegin(); riter != previousItems.rend(); riter++)
        {
            previousItemsBetterOrder << *riter;
        }

        QString name_previous_item = QInputDialog::getItem(nullptr,
                                                      QString("Previous item"),
                                                      QString("Previous item to start from : "),
                                                      previousItemsBetterOrder, 0, false, &chose_item);

        if(!chose_item)
        {
            return;
        }

        /* Decode chosen previous item by retrieving it in the map */
        LinkedItems::iterator chosenPrevIter = previousItemsMap.value(name_previous_item);

        bool chose_member;

        /* Find all existing IDs in previous item */

        QStringList previousIDs;

        QMap<int, Member>::const_iterator memberIter;

        /* Retrieve all members from the chosen previous item */

        std::cout << "Search IDs in chosen previous item : " << std::flush;
        for(memberIter = chosenPrevIter->m_members.begin(); memberIter != chosenPrevIter->m_members.end(); memberIter++)
        {
            previousIDs << QString("%1").arg(QString::number(memberIter->ID));
            std::cout << memberIter->memberID << ", " << std::flush;
        }
        std::cout << "finished." << std::endl << std::flush;

        /* If no member then no lunch */
        if(previousIDs.size() == 0)
        {
            QMessageBox::critical(nullptr, tr("Rename previous member"),
                                          tr("There are no members in the selected previous item."),
                                          QMessageBox::Ok, QMessageBox::Ok);
            return;
            std::cout << "Rename previous members finished with no members in chosen previous item." << std::endl << std::flush;
        }

        QString string_member_id_from_previous = QInputDialog::getItem(nullptr,
                                                      QString("Previous member number"),
                                                      QString("Member ID from previous item to be used : "),
                                                      previousIDs, 0, false, &chose_member);
        if(chose_member)
        {
            int member_id_from_previous = string_member_id_from_previous.toInt();


            /* Update member ID at and before chosen previous item */

            std::cout << "Update member ID before chosen previous item : " << std::flush;
            for(itemIter = chosenPrevIter;
                itemIter != m_items.begin();
                itemIter--)
            {
                std::cout << itemIter->name << std::flush;
                if(itemIter->m_members.contains(member_id_from_previous))
                {
                    /* Take and reinsert to new ID. */
                    std::cout << "+" << std::flush;
                    itemIter->m_members.insert(memberIDToPropagate, itemIter->m_members.take(member_id_from_previous));
                }
                else
                {
                    /* Do nothing. */
                }
                std::cout << ", " << std::flush;
            }
            std::cout << "finished." << std::endl << std::flush;

            }
        }
        else
        {
            /* Do nothing. */
        }
    }
    else
    {
        QMessageBox::critical(nullptr, tr("Apply to previous members"),
                             tr("This is the first item. There are no previous items."),
                             QMessageBox::Ok);

    }
    std::cout << "Apply to previous members finished." << std::endl << std::flush;
}

标签: qtiteratorqt5

解决方案


推荐阅读