问题描述
假设我有一个按值返回 std::vector
的函数:
Suppose I have a function that returns a std::vector
by value:
std::vector<int> buildVector();
使用基于范围的 for
迭代结果似乎很自然:
It would seem natural to iterate over the result using a range-based for
:
for (int i : buildVector()) {
// ...
}
问题:这样做安全吗?
我对标准的阅读(实际上,草案n4431) 表明它可能不是,尽管我很难相信委员会未能允许这种用法.我希望我的阅读是不正确的.
My reading of the standard (actually, draft n4431) suggests that it might not be, though I'm having a hard time believing that the committee failed to allow for this usage. I'm hoping that my reading is incorrect.
第 6.5.4 节定义了基于范围的 for
:
Section 6.5.4 defines the range-based for
:
for ( for-range-declaration : expression ) statement
具有以下脱糖:
{
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)
等
where range-init
is just ( expression )
, and at least for class types, begin-expr
is either __range.begin()
or begin(__range)
, etc.
在我的 buildVector
示例中,我认为 range-init
产生一个临时的,允许实现在 __range
之后立即销毁参考是绑定的.这意味着在评估 begin-expr
时,__range
引用可能已经悬空了.
In my buildVector
example, I think the range-init
produces a temporary, which the implementation is allowed to destroy immediately after the __range
reference is bound. This would mean that the __range
reference might already be dangling by the time begin-expr
is evaluated.
当然,写这个应该总是安全的:
Certainly, it should always be safe to write this:
std::vector<int> notATemporary = buildVector();
for (int i : notATemporary) {
// ...
}
但我希望我不必将此添加到我的问题列表中.
But I'm hoping I don't have to add this to my list of gotchas.
推荐答案
是的,它非常安全.
来自[class.temporary]/4-5:
From [class.temporary]/4-5:
在两种情况下,临时对象在与完整表达式结束不同的点被销毁.第一个上下文是调用默认构造函数时 [...]
第二个上下文是引用绑定到临时对象时.引用的临时对象绑定或作为引用绑定到的子对象的完整对象的临时对象 持续存在对于引用的生命周期,除了:
The second context is when a reference is bound to a temporary. The temporary to which the reference isbound or the temporary that is the complete object of a subobject to which the reference is bound persistsfor the lifetime of the reference except:
- 临时绑定到构造函数的ctor-initializer [...] 中的引用成员
- 临时绑定到函数调用中的引用参数 [...]
- 临时绑定到函数返回语句中返回值的生命周期 [...]
- 临时绑定到 new-initializer [...] 中的引用
- A temporary bound to a reference member in a constructor’s ctor-initializer [...]
- A temporary bound to a reference parameter in a function call [...]
- The lifetime of a temporary bound to the returned value in a function return statement [...]
- A temporary bound to a reference in a new-initializer [...]
这些例外都不适用.因此,临时对象在引用的生命周期内持续存在,__range
,这是整个循环.
None of those exceptions apply. The temporary thus persists for the lifetime of the reference, __range
, which is the entire loop.
这篇关于使用带有右值范围初始化的 C++11 基于范围的 for 循环是否安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!