假设我是新手C ++程序员。我有一个C ++容器;例如,向量:
std::vector<int> vec { 12, 34, 56, 78 };
我知道我可以通过一个简单的循环遍历所有元素:
for(std::vector<int>::size_type i = 0; i < vec.size(); i++) {
std::cout << vec[i] << '\n';
}
也许我甚至对现代C ++有所了解,所以我知道我可以使用range-for循环:
for(auto x : vec) {
std::cout << x << '\n';
}
但是现在,我要遍历元素以相反的顺序。基于范围的for循环将无法正常工作。在一个普通的循环中,我必须小心并避免下溢,所以也许是这样的事情? :
for(std::vector<int>::size_type i = 0; i < vec.size(); i++) {
std::cout << vec[vec.size() - i] << '\n';
}
但是-我不喜欢让循环计数器与我们正在查看的相反。但是,如果我从i
开始vec.size()-1
,则冒着在最后一个元素之后出现下溢的风险。所以也许我需要这样做?
for(std::vector<int>::size_type i = vec.size(); i > 0 ; i--) {
std::cout << vec[i - 1] << '\n';
}
嗯,那感觉也不对。我应该使用哪些惯用法来进行反向迭代,这些惯用法是安全的(即,很难弄错),美观且合理的简洁?
注意:
auto&
或const auto&
,因为新手编码人员通常不了解它们。首先,关于您的两个代码段:问题的一部分是它们对于实际的新手来说很容易出现错误-整数下溢,在比较中一一对应,忘记了i
表示什么,使用它作为普通索引等。因此,我绝对会推荐其他东西。同样,这些代码片段可能会多次调用vec.size()
,如果编译器的优化不够好,则意味着大量的重复工作。
您可以使用一对迭代器(std::rbegin
and std::rend
及其常量变量)对容器进行反向迭代,这些迭代器表示容器元素顺序的反向。看起来像这样:
std::rbegin
我首先选择了此选项,因为它(主要)与C ++ 98兼容。那时我们没有std::rend
和for(auto it = std::crbegin(vec); it != std::crend(vec); it++) {
std::cout << *it << std::endl;
}
,但是我们有std::rbegin()
的std::crbegin()
方法。 rbegin()
是在C ++ 11中引入的
您可以按摩容器-无需复制容器(尽管可能需要花费一些时间),因此您可以将结果用于护林器进行循环。 std::vector
的答案描述了启用以下代码的几种方法:
std::crbegin()
[它们涉及使用“基础结构”库(即Boost),或编写几行代码以在this SO question中返回一个迭代器对-这足以使C ++在auto reverse_view = /* magic involving vec; and not making a copy */
for(auto x : reverse_view) {
std::cout << *it << std::endl;
}
中使用。
最后,在C ++ 20中,这一切都变得更加容易-具有范围支持和std::pair
:
ranged-for loop
在某些情况下,反向迭代可能会很昂贵-因为向后移动或找到容器的末端并不总是琐碎或随意的。考虑一个单向列表(每个元素都带有指向下一个的指针)-每当您想向后移动时,都需要遍历整个列表直到当前元素,以了解前一个元素的位置。并非所有容器都像矢量...