【问题标题】:Will range based for loop in c++ preserve the index orderc++中基于范围的for循环是否会保留索引顺序
【发布时间】:2013-10-03 19:49:00
【问题描述】:

在c++11中,如果我在向量上使用基于范围的for循环,它会保证迭代顺序吗?

即以下代码块是否保证产生相同的输出?

vector<T> output;
vector<U> V;
for( auto v: V) output.push_back(f(v));

for(int i =0; i < V.size(); ++i) output.push_back(f(V[i])); 

如果不是vector 而是map 等怎么办?

【问题讨论】:

  • 你当然可以通过 auto&amp; 而不是 auto 来优化一些不必要的副本

标签: c++ for-loop c++11


【解决方案1】:

是的,它们是等价的。 6.5.4中的标准保证:

对于形式的基于范围的for语句

for ( for-range-declaration : expression ) statement

range-init等价于括号括起来的表达式(表达式)

对于一个基于范围的for语句的形式

for ( for-range-declaration : braced-init-list ) statement

range-init 等同于花括号初始化列表。在每种情况下,基于范围的 for 语句都等价于

{
  auto && __range = range-init;
  for ( auto __begin = begin-expr,
      __end = end-expr;
      __begin != __end;
      ++__begin ) {
    for-range-declaration = *__begin;
    statement
  }
}

其中__range__begin__end是仅为说明定义的变量,_RangeT是表达式的类型,begin-exprend-expr的确定如下:

——如果_RangeT是一个数组类型,begin-exprend-expr分别是__range__range + __bound,其中__bound是数组绑定。如果_RangeT是一个未知大小的数组或一个不完整类型的数组,则程序是非良构的;

— 如果_RangeT 是类类型,则在类_RangeT 的范围内查找不合格的ID beginend 好像通过类成员访问查找 (3.4.5),并且如果其中一个(或两者)找到至少一个声明,begin-exprend-expr 分别是 __range.begin()__range.end()

— 否则,begin-exprend-expr 分别是 begin(__range)end(__range),其中 beginend 使用参数相关查找 (3.4.2) 进行查找。出于此名称查找的目的,命名空间std 是一个关联的命名空间。

虽然您关于地图的问题有点荒谬。如果它是有序地图并且您正确地遍历地图,那么它们是等价的。如果它是一个无序的地图,那么你的问题并没有多大意义。

【讨论】:

    【解决方案2】:

    是的,这两个代码保证会做同样的事情。虽然我没有标准的链接,但您可以查看here。我引用:You can read that as "for all x in v" going through starting with v.begin() and iterating to v.end().

    【讨论】:

    • here 对表达式中的每个元素重复并顺序执行语句。
    【解决方案3】:

    是和否(取决于使用的容器):

    • 基于 for 的范围是一个类似于 for(iterator pos = range.begin(); pos != 范围.end(); ++pos) { /* 带有范围变量 = *pos */ ... }
    • 运算符 [] 可能会做一些不同的事情(例如,如果键不存在,则 std::map 运算符会查找键并创建一个新条目)

    例子:

    #include <iostream>
    #include <map>
    
    int main()
    {
        typedef std::map<int, int> map;
        map m = { { 0, 0 }, { 2, 2 }, { 4, 4 } };
        for(const auto& e : m) {
            std::cout << e.first << " ";
        }
        std::cout << std::endl;
        for(map::size_type i = 0; i < m.size(); ++i) {
            std::cout << m[i] << " ";
        }
        std::cout << std::endl;
        return 0;
    }
    

    结果是:

    0 2 4 
    0 0 2 0 4 
    

    (第二个结果可能是一脚好球,甚至是故意的)

    【讨论】:

    • 您可能应该指出,在此示例中,无论哪种方式,用户都在做一些非常错误的事情。如果您在map 上有键类型为int 的顺序索引,那么您不应该使用map,您应该使用dequevectorarray。如果您没有顺序索引,那么您应该使用迭代器进行迭代,而不是使用 for (int i = 0; i &lt; blah; ++i)
    猜你喜欢
    • 1970-01-01
    • 2013-01-04
    • 2013-03-23
    • 1970-01-01
    • 2011-11-03
    • 2016-10-31
    • 2019-04-17
    • 1970-01-01
    相关资源
    最近更新 更多