我需要从排序列表中删除前3项,为此逻辑我可以使用' erase'删除元素。但是,我想知道' pop_front'适用于这种情况。因此,我尝试了下面的代码,但它崩溃了(在一个循环后破坏了迭代器)。在这种情况下,我不知道为什么它会破坏迭代器。有人可以帮我这个。
int main(int argc, char *argv[])
{
list<int> l;
for (int i=1; i<=5; ++i)
{
l.push_back(i);
}
for (list<int>::iterator itr=l.begin(); itr != l.end(); ++itr)
{
if(*itr <= 3)
l.pop_front();
}
return 0;
}
答案 0 :(得分:2)
在这种情况下,我不知道它为什么会破坏迭代器。
请阅读documentation:
第一次迭代中的擦除元素的引用和迭代器无效。
itr
指向擦除的l.begin()
,然后无效迭代器上的++itr
失败。您需要在调用pop_front()
之前增加迭代器。但更好的是使用迭代器显式擦除以避免意外:
for (list<int>::iterator itr=l.begin(); itr != l.end(); )
{
if(*itr <= 3) l.erase( it++ );
else ++it;
}
此代码的行为可能与您的行为不同,因为无论itr
指向何处,您始终会删除第一个元素,但我认为您要删除小于或等于3的元素。
答案 1 :(得分:0)
所以这里有一些事情发生。
首先:你在迭代它时改变一个列表。通常,尝试这是一个坏主意。将列表视为链接列表。每个节点由其自己的值和指向下一个元素的指针/引用组成。通过弹出一个项目,你将其从列表中删除,然后迭代器将不再知道在哪里寻找下一个元素。它实际上比这更复杂(每种类型的标准集合都有某些定义的操作必须使迭代器无效,但它们在集合类型之间有所不同),但这是一般的想法。
第二:你没有删除索引小于3的元素,你试图删除值小于3的元素。在这种情况下逻辑上会起作用,因为前3个元素的值为1,2 ,和3。
为了解决你的问题,我会写下你的第二个循环:
for(int index=0; index<3; index++){
l.pop_front();
}
然后,如果您需要执行其他操作,则可以稍后遍历列表。
答案 2 :(得分:0)
感谢您的回复,
我想我找到了问题的答案:
答案:在循环中'使用列表开始启动迭代器'并在for循环块中我使用pop_front删除'list的第一个元素',一旦我们删除了第一个元素list.begin()更改为list中的下一个元素。但仍然没有迭代器。所以它变成悬空指针,接下来我们在下一个循环中访问悬空指针,因此它是转储代码。
通过gdb找到上面的信息。
Breakpoint 2, main (argc=1, argv=0x7fffffffdfd8) at list_erase.cpp:20
20 for (list<int>::iterator itr=l.begin(); itr != l.end(); ++itr)
(gdb) n
22 if(*itr <= 3)
(gdb) p *itr
$5 = (int &) @0x603020: 1
(gdb) p itr
$6 = {_M_node = 0x603010}
(gdb) p l.begin()
$7 = {_M_node = 0x603010}
(gdb) n
23 l.pop_front();
(gdb) n
20 for (list<int>::iterator itr=l.begin(); itr != l.end(); ++itr)
(gdb) p itr
$8 = {_M_node = 0x603010}
(gdb) p l.begin()
$9 = {_M_node = 0x603030}
(gdb) n
22 if(*itr <= 3)
(gdb) p itr
$10 = {_M_node = 0x0}
(gdb) p l.begin()
$11 = {_M_node = 0x603030}
要通过'pop_front'修复我的问题,我应该这样做:
for (list<int>::iterator itr=l.begin(); itr != l.end(); )
{
if(*itr <= 3)
{
l.pop_front();
itr = l.begin();
// OR
// itr = l.erase(l.begin());
}else
++itr;
}
'pop_front就像这样工作': 因为,std :: list pop_front实现如下:
void pop_front() { erase(begin()); }
在pop_front代码实现中,我们没有捕获列表的下一个元素的返回值,因此在擦除之后它将是悬空指针。所以,预计崩溃。
让我知道,如果错了..