[英]STL iterator before std::map::begin()
In C++11's std::map
, is there some valid iterator x such that ++ x is guaranteed to equal map::begin()
? 在C ++ 11的
std::map
,是否有一些有效的迭代器x使得++ x保证等于map::begin()
? I would like to detect if a function I just called (mine) has walked an iterator off the front of a function. 我想检测一下我刚刚调用的函数(我的)是否已经从函数前面走了一个迭代器。 The function will move the iterator exactly one position backward.
该函数将迭代器向后移动一个位置。
Does the answer hold for the rest of the library? 答案是否适用于图书馆的其他部分?
No, iterators before the beginning in std
containers are all UB (except for reverse iterators, which will probably not solve your problem). 不,在
std
容器中开始之前的迭代器都是UB(反向迭代器除外,这可能无法解决您的问题)。
You probably need to fix the function in question. 您可能需要修复有问题的功能。 Failing that, wrap it and catch the bad behavior before you call it.
如果失败了,请在调用之前将其包装并捕获不良行为。 Failing that, you could insert a negative infinity element into the
map
key type ordering, and add a sentinal value. 如果不这样做,您可以在
map
键类型排序中插入负无穷大元素,并添加一个sentinal值。 Failing that, you could write iterator adapters that wrap your map
iterators with ones that can go one-before-beginning without UB. 如果做不到这一点,你可以编写迭代器适配器来封装你的
map
迭代器,它们可以在没有UB的情况下开始。
These are ordered in my order of recommendation, roughly. 这些是按我的推荐顺序排列的。 Each has ways it could fail, and they get more error prone and dangerous as my recommendation gets more remote.
每种方法都有失败的方式,而且随着我的推荐变得更加偏远,它们会更容易出错并且更加危险。
It's very important to realize that Standard Library containers are semi-open ranges [begin, end)
, ie you can iterate one-past-the-end. 非常重要的是要意识到标准库容器是半开放范围
[begin, end)
,即你可以迭代一次过去。 For bidirectional (and random) iterators you can also do --end()
and come back from the brink. 对于双向(和随机)迭代器,您也可以执行
--end()
并从边缘返回。 Dereferencing one-past-the-end by *end()
is undefined behavior, and so is decrementing the begin iterator by --begin()
or begin() - 1
. 通过
*end()
--begin()
引用一个*end()
是未定义的行为,因此通过--begin()
或begin() - 1
递减开始迭代器。 There is only one exception to this: std::forward_list
which has a non-dereferenceable iterator before_begin()
that satisfies ++before_begin() == begin()
(but note that for a forward_list
you cannot decrement begin()
either). 这只有一个例外:
std::forward_list
有一个before_begin()
引用的迭代器before_begin()
,它满足++before_begin() == begin()
(但请注意,对于forward_list
你也不能减少begin()
)。
This fundamental asymmetry for bidirectional iterators means that reverse iterators are thin wrappers around regular iterators. 双向迭代器的这种基本不对称性意味着反向迭代器是常规迭代器周围的薄包装器。 In most Standard Library implementations they simply contain a copy
base_
of the underyling iterator. 在大多数标准库实现中,它们只包含underyling迭代器的副本
base_
。 Incrementing a std::reverse_iterator
calls something like --base_; return *this;
增加
std::reverse_iterator
调用类似--base_; return *this;
--base_; return *this;
, and dereferencing it does auto old = base_; return *--old;
,并取消引用它会
auto old = base_; return *--old;
auto old = base_; return *--old;
. 。 At no point is the underlying iterator decremented to before
begin()
, and no dereferencing of end()
is done that way. 在
begin()
之前,底层迭代器决不会减少,并且不会以这种方式解除end()
解除引用。
Below are the four ways to iterate over a container supporting bidirectional or random iterators, and the relations between the various iterators ( .base()
converts a std::reverse_iterator
back to its underlying iterator) 下面是迭代支持双向或随机迭代器的容器的四种方法,以及各种迭代器之间的关系(
.base()
将std::reverse_iterator
转换回其底层迭代器)
#include <iomanip>
#include <iostream>
#include <iterator>
#include <map>
#include <string>
int main()
{
auto c = std::map<int, std::string>{ {1, "hello"}, {2, "world"} };
{ // 1) forward iteratation
auto it = begin(c);
for (; it != end(c); ++it){}
std::cout << std::boolalpha << (it == c.rbegin().base()) << "\n";
}
{ // 2) meh, backward iteration
auto it = end(c);
for (; it != begin(c); --it){}
std::cout << std::boolalpha << (it == c.rend().base()) << "\n";
}
{ // 2') better: reverse iteration
auto it = c.rbegin();
for (; it != c.rend(); ++it){}
std::cout << std::boolalpha << (it.base() == begin(c)) << "\n";
}
{ // 1') backward reverse, better avoid this
auto it = c.rend();
for (; it != c.rbegin(); --it){}
std::cout << std::boolalpha << (it.base() == end(c)) << "\n";
}
}
If you have data structure that should support bidirectional iteration but there are no member iterators .rbegin()
or rend()
, you can easily define them yourself by std::reverse_iterator(end())
and std::reverse_iterator(begin())
, respectively (this is also the way the Standard Library usually implements them). 如果你的数据结构应该支持双向迭代但是没有成员迭代器
.rbegin()
或rend()
,你可以通过std::reverse_iterator(end())
和std::reverse_iterator(begin())
自己定义它们。 std::reverse_iterator(begin())
,分别(这也是标准库通常实现它们的方式)。
By "walk the iterator off the front" I presume you are decrementing a forward iterator something like this: 通过“从前面走迭代器”我假设你正在递减这样的前向迭代器:
// don't do this:
for(it = mymap.end(); --it >= mymap.begin(); ) { ... }
Instead, increment a reverse iterator like this: 相反,增加一个反向迭代器,如下所示:
// this is better:
for(it = mymap.rbegin(); it != mymap.rend(); ++it) { ... }
-Jesse -Jesse
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.