如何从 stl 数据结构中删除反向迭代器?
由于某种原因,以下代码失败。 您不能简单地通过使用其 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();
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_iterators。 它想要真实的东西。
For some reason the following code fails. You can't simply erase a reverse_iterator by using its base() method.
#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;
}
}
How does one go about correctly doing the above? Given a reverse_iterator that corresponds to something you want to erase, how do you erase it?
Note, erase won't take reverse_iterators unfortunately. It wants the real thing.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
显然,解决方案是 base() 返回的是 1。 以下恒等式适用于反向迭代器:
或者换句话说,反向迭代器始终是其基础的常规迭代器的一次传递。 不知道为什么。
在 GCC 中,
只需更改
为
我非常好奇为什么上面的身份有意义。
在 Visual Studio 中
回到工作并在 Visual Studio 中尝试此操作,我发现上述解决方案不太有效。 “nextIter”在擦除时变得无效。 相反,您需要保存擦除中的临时值以获取下一个迭代器,而不是像上面那样保留 nextIter。
所以最终的解决方案是
注意,关联容器不会从擦除返回迭代器。 所以这个解决方案不适用于地图、多重地图等。
Apparently the solution is what base() returns is 1 off. The following identity holds for a reverse_iterator:
Or in other words, the reverse_iterator is always one pass the regular iterator it is the base of. Not sure why.
In GCC
Simply change
to
I'm definitely curious though as to why the identity above makes sense.
In Visual Studio
Coming back into work and trying this in visual studio, I see the above solution doesn't quite work. The "nextIter" becomes invalid on the erase. Instead, you need to save away the temporary from the erase to get the next iterator instead of keeping around a nextIter like above.
So the final solution is
Note, associative containers do not return an iterator from erase. So this solution wouldn't work for map, multimap, etc.
当您使用反向迭代器进行迭代并想要使用 base() 修改其容器时,请始终记住,reverse_iterator 始终基于原始顺序的下一个迭代器。 这有点不直观,但它实际上使代码更简单:
在这个示例中,不需要保留“下一个”迭代器,因为基本迭代器没有失效! (在处理普通迭代器时,我们确实需要它。)
反向迭代器的行为在处理单个项目时会产生奇怪的逐一困难,但实际上它简化了范围:
使用与
When you iterate with a reverse iterator and want to use base() to modify its container, always keep in mind that a reverse_iterator is always based on the next iterator from the original order. It's a little unintuitive but it actually makes the code simpler:
In this example, there is not need to keep a "next" iterator since the base iterator is not invalidated! (We do need it when dealing with normal iterators.)
The behavior of reverse iterators creates weird off-by-one difficulties when treating with a single item but in facts it simplify ranges:
is using exactly the same objects (in reverse order) as
1 来自 map::erase,我们知道它只需要迭代器;
2 来自 reverse_iterator::base,我们知道
&*(reverse_iterator ( i ) ) == &*( i – 1 ).
因此,你可以用erase(--r_v.base())来擦除“”指向的元素r_v”(和“current-1”):
1 from map::erase, we know it only takes
iterator
;2 from reverse_iterator::base, we know
&*(reverse_iterator ( i ) ) == &*( i – 1 ).
Therefore, you can erase(--r_v.base()) to erase the element pointed by "r_v" (and "current-1"):
使用迭代器本身调用
erase
(无需使用base
)。另外,您不需要单独的“下一个”迭代器(请参阅上面的更改)。 更好的方法是使用 std::remove_if (或类似的函数)。
Call
erase
with the iterator itself (no need to usebase
).Also, you don't need that separate "next" iterator (see above changes). An even better way to do this is to use
std::remove_if
(or a function like it).