使用带有rvalue range-init的C ++ 11基于范围的for循环是否安全?

时间:2015-05-26 01:45:32

标签: c++ c++11 foreach

假设我有一个按值返回std::vector的函数:

std::vector<int> buildVector();

使用基于范围的for

迭代结果似乎很自然
for (int i : buildVector()) {
  // ...
}

问题:这样做是否安全?

我对标准的阅读(实际上,草案n4431)表明它可能不是,尽管我很难相信委员会未能允许这种用法。我希望我的阅读不正确。

第6.5.4节定义了基于范围的for

for ( for-range-declaration : expression ) statement

与以下desugaring:

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

其中range-init只是( expression ),至少对于类类型,begin-expr可以是__range.begin()begin(__range)等。

在我的buildVector示例中,我认为range-init会生成一个临时的,允许实现在__range引用绑定后立即销毁。这意味着__range引用可能已经在评估begin-expr时悬空。

当然,写这个应该总是安全的:

std::vector<int> notATemporary = buildVector();
for (int i : notATemporary) {
  // ...
}

但我希望我不必将其添加到我的陷阱列表中。

1 个答案:

答案 0 :(得分:20)

是的,这是非常安全的。

来自[class.temporary] / 4-5:

  

有两种情况下,临时表在不同于完整表达结束时被摧毁。第一个上下文是调用默认构造函数[...]

     

第二个上下文是引用绑定到临时的。引用所在的临时值   绑定或临时是绑定引用的子对象的完整对象仍然存在   参考的生命周期除外:

     
      
  • 临时绑定到构造函数的 ctor-initializer [...]
  • 中的引用成员   
  • 临时绑定到函数调用[...]
  • 中的引用参数   
  • 函数返回语句[...]
  • 中临时绑定到返回值的生命周期   
  • 临时绑定到 new-initializer [...]
  • 中的引用   

这些例外都不适用。因此临时值持续到引用的生命周期__range,这是整个循环。