假设我有一个按值返回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) {
// ...
}
但我希望我不必将其添加到我的陷阱列表中。
答案 0 :(得分:20)
是的,这是非常安全的。
来自[class.temporary] / 4-5:
有两种情况下,临时表在不同于完整表达结束时被摧毁。第一个上下文是调用默认构造函数[...]
第二个上下文是引用绑定到临时的。引用所在的临时值 绑定或临时是绑定引用的子对象的完整对象仍然存在 参考的生命周期除外:
- 临时绑定到构造函数的 ctor-initializer [...]
中的引用成员- 临时绑定到函数调用[...]
中的引用参数- 函数返回语句[...]
中临时绑定到返回值的生命周期- 临时绑定到 new-initializer [...]
中的引用
这些例外都不适用。因此临时值持续到引用的生命周期__range
,这是整个循环。