C++ 访问迭代器指向的列表元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5146057/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Accessing list element pointed by an iterator
提问by Farhan
The natural answer would be to dereference the iterator and get the value. However, I'm stuck at using VC++ 2010 which doesn't allow dereferencing the list iterator (or does it?) I'm confused because, at one point, I need to dereference two list iterators and compare their values using: (*it) == (*it2) The program crashes with an error, only due to this line. I'm also dereferencing the iterator in a statement: printf("%d\n", (*it)); This works perfectly fine though. So, is there any way to access an element without dereferencing or using a cliext::list.
自然的答案是取消引用迭代器并获取值。但是,我坚持使用 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--;
}
}
The error I get is:
我得到的错误是:
Debug Assertion Failed
调试断言失败
Expression: list iterator not dereferencable
表达式:列表迭代器不可解引用
Surprisingly the same code runs without a problem when compiled on DevC++ (MinGW)
令人惊讶的是,在 DevC++ (MinGW) 上编译时,相同的代码运行没有问题
回答by Mark B
You can in fact dereference list
iterators. If you couldn't, your comparison code wouldn't have even compiled. Most likely you're accidentally dereferencing an end
iterator though rather than a valid one, causing the crash. Without more code it's hard to make further observations.
实际上,您可以取消引用list
迭代器。如果你不能,你的比较代码甚至不会被编译。很可能你不小心取消了一个end
迭代器而不是一个有效的迭代器,导致崩溃。如果没有更多的代码,就很难进行进一步的观察。
EDIT: I can't make out quite what it is you're trying to do. The code you've written erases all the elements between two equal elements. I'll assume you're actually trying to remove all the duplicate elements, and that sorting the list first for performance isn't a concern/option.
编辑:我无法弄清楚你想要做什么。您编写的代码会擦除两个相等元素之间的所有元素。我假设您实际上是在尝试删除所有重复元素,并且首先对列表进行排序以提高性能并不是一个问题/选项。
EDIT2: I saw in a comment below you really want to delete the range. Updated my code.
EDIT2:我在下面的评论中看到你真的想删除范围。更新了我的代码。
Then try something like this:
然后尝试这样的事情:
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;
}
}
回答by young
"select" Isn't Broken.
It is rare to find a bug in the OS or the compiler, or even a third-party product or library. The bug is most likely in the application. - from The Pragmatic Programmer
“选择”不坏。
很少在操作系统或编译器,甚至第三方产品或库中发现错误。该错误最有可能出现在应用程序中。- 来自务实的程序员
It's highly likely due to your problem, not MS. Make it sure that your iterators are not invalidatedwhile you are using them. You could accidentally erase the element which invalidate the iterator. Check this thread: What is the lifetime and validity of C++ iterators?and Good Luck! :)
这很可能是由于您的问题,而不是 MS。确保您的迭代器在使用时不会失效。您可能会意外删除使迭代器无效的元素。检查这个线程:什么是 C++ 迭代器的生命周期和有效性?还有祝你好运!:)
UPDATE:
更新:
As I mentioned earlier, you are invalidating your iterators by erasing them in the middle of the loop. See my code below to do it properly.
正如我之前提到的,您通过在循环中间擦除它们来使迭代器无效。请参阅下面的代码以正确执行此操作。
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;
}
}
回答by vrrathod
Its surely your code. It has two problems as far as I can see. Checkout the comments.
它肯定是您的代码。据我所知,它有两个问题。查看评论。
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--;
}
回答by user470379
Try this instead:
试试这个:
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;
}
}
}
This new version avoids two errors in the original version of the code. First, the code now properly handles the edge conditions of the inner for loop. In the original code, the for loop allowed it2
to go up to sList.end()-1
, but then the next line incremented it to sList.end()
on the last iteration. The next line then dereferenced this (invalid) iterator which is one past the last value of the list (because that's what end
returns, it's not an iterator to the last value of the list).
这个新版本避免了原始版本代码中的两个错误。首先,代码现在可以正确处理内部 for 循环的边缘条件。在原始代码中,for 循环允许it2
上升到sList.end()-1
,但是下一行在sList.end()
最后一次迭代时将其增加到。下一行然后取消引用这个(无效)迭代器,它是列表最后一个值之后的一个(因为它是end
返回的,它不是列表最后一个值的迭代器)。
Second, calling erase
invalidates any iterators pointing to any of the values erased (which in this case would including any iterators from it
to it2-1
). By starting at the end of the list and working our way forward, we no longer have to continue iterating when we find the value, and can break
from the inner loop once we find it. erase
returns an iterator to the next element in the list after the elements deleted (which would be the next element we want to try for it
). But since the for loop increments it
, we subtract 1 from what's returned by erase
so that it
points to the right element once it's incremented at the beginning of the next loop iteration. (Note that in the case that it
points to the first element, we actually temporarily set it to point an element before the beginning of the list; however, this is only temporary and we don't dereference the iterator while it's pointing outside the list).
其次,调用erase
会使指向任何已擦除值的任何迭代器失效(在这种情况下将包括从it
to 的任何迭代器it2-1
)。通过从列表的末尾开始并继续前进,我们在找到值时不再需要继续迭代,并且break
一旦找到它就可以从内部循环中进行。erase
在元素删除后返回列表中下一个元素的迭代器(这将是我们想要尝试的下一个元素it
)。但是由于 for 循环 increments it
,我们从返回的值中减去 1,erase
以便it
在下一次循环迭代开始时它增加时指向正确的元素。(请注意,在这种情况下it
指向第一个元素,我们其实是临时设置它指向列表开头之前的一个元素;然而,这只是暂时的,当它指向列表之外时,我们不会取消引用迭代器)。
Note that this preserves the original behavior of the code for the case 0 2 3 4 5 1 6 7 8 0 9 10 11 1
. You haven't explicitly stated what order the deletes should occur (should the elements between 0
's be erased first, or the elements between 1
's, or do we need to add additional logic to actually erase the whole range except for the first 0
and 1
?), but this code behaves like the original and erases the numbers in between the 0
's and ignores the fact that the 9 10 11
afterwards was original in between matching 1
's.
请注意,这保留了案例代码的原始行为0 2 3 4 5 1 6 7 8 0 9 10 11 1
。您还没有明确说明删除应该发生的顺序(应该0
先擦除 's之间的元素,还是1
's之间的元素,或者我们是否需要添加额外的逻辑来实际擦除除第一个0
和之外的整个范围1
? ),但此代码的行为与原始代码相同,并擦除0
's之间的数字,并忽略了9 10 11
after 是匹配1
's之间的原始代码这一事实。
回答by Greg Domjan
It is really unclear what this code snippet or whatever code you get the error from is trying to do.
目前还不清楚这个代码片段或您从中得到错误的任何代码试图做什么。
It appears what you want to do is for each item delete all items between it and the next matching item, or maybe it is the last matching item.
看起来您想要做的是为每个项目删除它与下一个匹配项目之间的所有项目,或者它可能是最后一个匹配项目。
your inner loop iteration is double stepping from the loop increment and then incrementing again inside the loop.
您的内部循环迭代是从循环增量开始双步执行,然后在循环内再次增加。
your not checking if you have hit/passed the end of the list after doing the inner iteration which could lead to the crash when doing the comparison
在进行内部迭代后,您没有检查是否已命中/通过列表末尾,这可能会在进行比较时导致崩溃
after erasing you decrement it2, which then puts it before what it1 was (and is now deleted).
擦除后,您递减 it2,然后将它放在 it1 之前(现在已删除)。