自然的答案是取消引用迭代器并获取值。但是,我坚持使用VC ++ 2010,它不允许解除引用列表迭代器(或者是吗?) 我很困惑,因为在某一点上,我需要取消引用两个列表迭代器并使用以下方法比较它们的值: (* it)==(* it2) 程序因错误而崩溃,仅此行。我也在声明中取消引用迭代器: printf(“%d \ n”,(* it)); 这虽然工作得很好。 那么,有没有办法在不解除引用或使用cliext :: list的情况下访问元素。
for (it=sList.begin(); it != sList.end(); it++)
{
for (it2=it; it2 != sList.end(); it2++)
{
it2++;
if ((*it) == (*it2))
{
sList.erase(it, it2);
}
it2--;
}
}
我得到的错误是:
Debug Assertion Failed
Expression:list iterator not dereferencable
令人惊讶的是,在DevC ++(MinGW)
上编译时,相同的代码运行没有问题答案 0 :(得分:4)
您实际上可以取消引用list
迭代器。如果你不能,你的比较代码甚至不会编译。很可能你不小心解除引用end
迭代器而不是有效迭代器,导致崩溃。没有更多的代码,很难进一步观察。
EDIT2:我在下面的评论中看到你真的要删除范围。更新了我的代码。
然后尝试这样的事情:
for (it=sList.begin(); it != sList.end(); ++it)
{
it2 = it;
++it2;
while(it2 != sList.end())
{
if ((*it) == (*it2))
{
it = it2 = sList.erase(it, it2); // Reset it as well since it will be blown away. It'll still point to the same value it did before though.
}
else
++it2;
}
}
答案 1 :(得分:1)
“选择”不会破碎。
很少在操作系统中找到错误或 编译器,甚至是第三方 产品或图书馆。这个bug最多 可能在申请中。 - 来自 The 务实的程序员
这很可能是由于你的问题,而不是MS。在使用它们时确保您的迭代器未失效。您可能会意外删除使迭代器无效的元素。检查此帖子:What is the lifetime and validity of C++ iterators? 还有祝你好运! :)
更新:
正如我前面提到的,你通过在循环中间擦除它们来使你的迭代器失效。请参阅下面的代码以正确完成。
std::list<int>::iterator EraseElements(std::list<int>& sList, std::list<int>::iterator start)
{
for (std::list<int>::iterator itor1 = start; itor1 != sList.end(); ++itor1)
{
std::list<int>::iterator itor2(itor1);
++itor2;
for ( ; itor2 != sList.end(); ++itor2)
{
if ((*itor1) == (*itor2))
{
return sList.erase(itor1, itor2);
}
}
}
return sList.end();
}
void main()
{
// Test
list<int> sList;
sList.push_back(1);
// elements will be erased
sList.push_back(2);
sList.push_back(3);
//
sList.push_back(2);
sList.push_back(4);
sList.push_back(5);
// elements will be erased
sList.push_back(6);
sList.push_back(7);
//
sList.push_back(6);
list<int>::iterator next = sList.begin();
while (next != sList.end())
{
next = EraseElements(sList, next);
}
// It will print 1 2 4 5 6
for (std::list<int>::const_iterator itor = sList.begin(); itor != sList.end(); ++itor)
{
cout << *itor << endl;
}
}
答案 2 :(得分:1)
肯定是你的代码。就我所见,它有两个问题。查看评论。
for (it2=it; it2 != sList.end(); it2++)
{
it2++;
// there is no guarantee that it2 will now be valid
// it should be validated again
if ((*it) == (*it2))
{
// you should not modify the list here.
// this will invalidate your iterators by default.
sList.erase(it, it2);
}
it2--;
}
答案 3 :(得分:1)
请改为尝试:
for (it=sList.begin(); it != sList.end(); it++)
{
for (it2=sList.end()-1; it2 != it+1; it2--)
{
if ((*it) == (*it2))
{
it = sList.erase(it, it2)-1;
break;
}
}
}
此新版本避免了原始版本代码中的两个错误。首先,代码现在正确处理内部for循环的边缘条件。在原始代码中,for循环允许it2
上升到sList.end()-1
,但是下一行在最后一次迭代时将其递增到sList.end()
。然后下一行取消引用这个(无效的)迭代器,它是一个超过列表最后一个值的迭代器(因为这是end
返回的内容,它不是列表最后一个值的迭代器。)
其次,调用erase
使任何指向已擦除的值的迭代器无效(在这种情况下,它将包括从it
到it2-1
的任何迭代器)。通过从列表的末尾开始并继续前进,我们不再需要在找到值时继续迭代,并且一旦找到它就可以从内循环中break
。 erase
在删除元素后返回列表中下一个元素的迭代器(这将是我们想要为it
尝试的下一个元素)。但是由于for循环递增it
,我们从erase
返回的值中减去1,这样it
一旦在下一个循环迭代开始时递增,就指向右边的元素。 (注意,在it
指向第一个元素的情况下,我们实际上暂时将其设置为在列表开头之前指向一个元素;但是,这只是临时的,我们不会取消引用迭代器,而它是指向列表之外)。
请注意,这会保留案例0 2 3 4 5 1 6 7 8 0 9 10 11 1
的代码的原始行为。你没有明确说明删除应该发生的顺序(首先要删除0
之间的元素,还是1
之间的元素,或者我们是否需要添加额外的逻辑擦除除第一个0
和1
之外的整个范围?),但此代码的行为与原始代码相同,并删除0
之间的数字,并忽略9 10 11
之间的数字{1}}之后在匹配1
之间是原创的。
答案 4 :(得分:0)
目前还不清楚这段代码片段或您收到错误的代码是什么。
你想要做的就是每个项目删除它与下一个匹配项目之间的所有项目,或者它可能是最后一个匹配的项目。
你的内循环迭代是从循环增量双重步进,然后在循环内再次递增。
你没有检查你是否在进行内部迭代后命中/通过了列表的末尾,这可能会导致比较时发生崩溃
擦除后,你减去it2,然后将它放在it1之前(现在被删除)。