我知道会要求我提供一个最小的示例,但我不确定一点都不能提出,否则不会很小。但是我仍然可以从这次讨论中学到有价值的知识。
因此,我在QLinkedList中组织了一系列给定类的数据项。为用户提供了一个界面,该界面允许浏览这些数据并进行编辑。特别是,某些可能的编辑操作需要修改QLinkedList中的多个条目-例如所有后续或所有先前的条目。还可以将项目添加或删除到列表中,然后进行编辑。
在代码中,我只是简单地使迭代器保持最新状态,该迭代器指向链中名为m_currentItem
的当前数据项。然后,我用它来显示当前项目中的数据,从当前循环到结束或开始。我要求此迭代器在应用程序的整个执行过程和整个生命周期内都是有效的,即使添加或删除项也是如此。当用户按下“下一个”或“上一个”时,迭代器将简单地递增或递减。当用户删除列表中的一项(最后一项除外)时,迭代器将指向下一个条目,并显示其内容。现在,当用户在列表中添加项目时,m_currentItem
便指向该新项目。
这是哪里出错了:在这些向后或向前循环上。它们经常(但不总是...)检查结束条件并继续输入未知数据,直到发生严重崩溃为止。有时,它还会循环回到列表中的第一个元素(!!!),这对ya来说是无限循环。
这是我代码中的一个示例,有什么明显错误的地方吗?关于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。
例如如果我们有A-B-C-D-E-F并且用户在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;
}