在C ++ 11的std::map
中,是否有一些有效的迭代器 x ,以致++ x 保证等于map::begin()
?我想检测一下我刚刚调用的函数(我的)是否已经从函数前面走了一个迭代器。该函数将迭代器正好向后移动一个位置。
答案是否适用于图书馆的其他部分?
答案 0 :(得分:4)
不,std
容器中开头之前的迭代器都是UB(反向迭代器除外,这可能无法解决您的问题)。
您可能需要修复有问题的功能。如果失败了,请在调用之前将其包装并捕获不良行为。如果做不到这一点,您可以在map
键类型排序中插入负无穷大元素,并添加一个sentinal值。如果做不到这一点,您可以编写迭代器适配器,将map
迭代器包装成可以在没有UB的情况下先行开头的迭代器。
这些是按我的推荐顺序排列的。每种方法都有失败的方式,而且随着我的推荐变得更加偏远,它们会更容易出错并且更加危险。
答案 1 :(得分:4)
非常重要的是要认识到标准库容器是半开放范围[begin, end)
,即你可以迭代一次。对于双向(和随机)迭代器,您也可以执行--end()
并从边缘返回。通过*end()
取消引用一个过去是未定义的行为,因此通过--begin()
或begin() - 1
递减开始迭代器。只有一个例外:std::forward_list
具有满足before_begin()
的不可解除引用的迭代器++before_begin() == begin()
(但请注意,对于forward_list
,您无法递减begin()
或者)。
双向迭代器的这种基本不对称性意味着反向迭代器是常规迭代器周围的薄包装器。在大多数标准库实现中,它们只包含underyling迭代器的副本base_
。增加std::reverse_iterator
调用类似--base_; return *this;
的内容,并取消引用
它auto old = base_; return *--old;
。在任何时候底层迭代器都不会减少到begin()
之前,并且不会以这种方式解除对end()
的解除引用。
以下是迭代支持双向或随机迭代器的容器的四种方法,以及各种迭代器之间的关系(.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";
}
}
如果您的数据结构应支持双向迭代,但没有成员迭代器.rbegin()
或rend()
,您可以通过std::reverse_iterator(end())
和std::reverse_iterator(begin())
自行定义它们,分别(这也是标准库通常实现它们的方式)。
答案 2 :(得分:1)
通过&#34;走向前面的迭代器&#34;我认为你正在递减这样的前向迭代器:
// don't do this:
for(it = mymap.end(); --it >= mymap.begin(); ) { ... }
相反,增加一个反向迭代器,如下所示:
// this is better:
for(it = mymap.rbegin(); it != mymap.rend(); ++it) { ... }
-Jesse