由于某种原因,以下代码失败。您不能简单地使用其base()方法擦除reverse_iterator。
#include <set>
#include <iostream>
int main()
{
std::set<int> setOfInts;
setOfInts.insert(1);
setOfInts.insert(2);
setOfInts.insert(3);
std::set<int>::reverse_iterator rev_iter = setOfInts.rbegin();
std::set<int>::reverse_iterator nextRevIter = setOfInts.rbegin();
++nextIter;
while ( rev_iter != setOfInts.rend())
{
// Find 3 and try to erase
if (*rev_iter == 3)
{
// SEGFAULT HERE
setOfInts.erase( rev_iter.base());
}
rev_iter = nextRevIter;
++nextRevIter;
}
}
如何正确地完成上述操作?如果reverse_iterator对应于您要擦除的内容,那么如何删除它?
注意,不幸的是,擦除不会使用reverse_iterator。它想要真实的东西。
答案 0 :(得分:18)
显然,解决方案是base()返回的是1。对于reverse_iterator,以下标识成立:
&*(reverse_iterator(i)) == &*(i - 1)
或者换句话说,reverse_iterator始终是一个通过它的基础的常规迭代器。不知道为什么。
只需更改
// SEGFAULT HERE
setOfInts.erase( rev_iter.base());
到
// WORKS!
setOfInts.erase( --rev_iter.base());
我很清楚,为什么上面的身份才有意义。
回到工作中并在visual studio中尝试这个,我看到上面的解决方案不太有效。擦除时“nextIter”变为无效。相反,你需要将擦除中的临时值保存起来以获得下一个迭代器,而不是保持像上面那样的nextIter。
set<int>::iterator tempIter = setOfInts.erase(--rev_iter.base());
rev_iter = setOfInts.erase(tempIter);
所以最终的解决方案是
int main()
{
using namespace std;
set<int> setOfInts;
setOfInts.insert(1);
setOfInts.insert(2);
setOfInts.insert(3);
set<int>::reverse_iterator rev_iter = setOfInts.rbegin();
while ( rev_iter != setOfInts.rend())
{
// Find 3 and try to erase
if (*rev_iter == 3)
{
cout << "Erasing : " << *rev_iter;
set<int>::iterator tempIter = setOfInts.erase( --rev_iter.base());
rev_iter = set<int>::reverse_iterator(tempIter);
}
else
{
++rev_iter;
}
}
}
注意,关联容器不会从erase返回迭代器。所以这个解决方案不适用于map,multimap等。
答案 1 :(得分:3)
当您使用反向迭代器进行迭代并希望使用base()来修改其容器时,请始终记住,reverse_iterator始终基于原始顺序中的下一个迭代器。这有点不直观,但它实际上使代码更简单:
#include <set>
int main()
{
std::set<int> setOfInts;
setOfInts.insert(1);
setOfInts.insert(2);
setOfInts.insert(3);
typedef std::set<int>::reverse_iterator RevIter;
RevIter rev_iter = setOfInts.rbegin();
while (rev_iter != setOfInts.rend())
{
// Find 3 and try to erase
if (*rev_iter == 3)
setOfInts.erase(--rev_iter.base());
++rev_iter;
}
}
在这个例子中,不需要保留“下一个”迭代器,因为基本迭代器没有失效! (在处理普通迭代器时我们确实需要它。)
反向迭代器的行为在处理单个项目时会产生奇怪的一对一困难,但事实上它简化了范围:
riValue = find(riEnd.base(), riBegin.base(), value);
使用与
完全相同的对象(顺序相反)iValue = find(riBegin, riEnd, value);
答案 2 :(得分:0)
1,我们知道只需要iterator
;
2,我们知道&*(reverse_iterator ( i ) ) == &*( i – 1 ).
因此,您可以擦除( - r_v.base())以擦除“r_v”(和“current-1”)指向的元素:
r_v+1 r_v r_v-1
current-2 current-1 current
答案 3 :(得分:-3)
使用迭代器本身调用erase
(无需使用base
)。
#include <set>
#include <iostream>
int main()
{
std::set<int> setOfInts;
setOfInts.insert(1);
setOfInts.insert(2);
setOfInts.insert(3);
std::set<int>::reverse_iterator rev_iter = setOfInts.rbegin();
while (rev_iter != setOfInts.rend())
{
// Find 3 and try to erase
if (*rev_iter == 3)
{
rev_iter = setOfInts.erase(rev_iter);
}
else
{
++rev_iter;
}
}
}
此外,您不需要单独的“下一个”迭代器(请参阅上面的更改)。更好的方法是使用std::remove_if
(或类似函数)。