使用rvalue range-init的C ++ 11基于范围的for循环安全吗? [英] Is it safe to use a C++11 range-based for-loop with an rvalue range-init?
问题描述
假设我有一个函数根据值返回一个 std :: vector
:
的std ::矢量< INT> buildVector();
使用基于范围的来遍历结果是很自然的
:
for(int i:buildVector()){
// .. 。
}
问题:安全吗?
是,这是完全安全的。
从[class.temporary] / 4-5:
两种情况下临时被毁坏在一个不同的点,而不是完全压缩的结束。第一个上下文是当一个默认的构造函数被调用时[/ b]
第二个上下文是当一个引用绑定到一个临时的时候。引用是
绑定的临时引用或引用所绑定到的子对象的完整对象的临时引用在引用的整个生命周期中持续存在
,除了
- 临时绑定到构造函数的 ctor-initializer 中的引用成员
- 临时绑定到函数调用中的引用参数[/ b]
- 函数返回语句中返回值的临时绑定的生命周期[ ...]
- 临时绑定到 new-initializer 中的引用
这些例外均不适用。因此,临时引用的持续时间是 __ range
,这是整个循环。
Suppose I have a function that returns a std::vector
by value:
std::vector<int> buildVector();
It would seem natural to iterate over the result using a range-based for
:
for (int i : buildVector()) {
// ...
}
Question: Is it safe to do so?
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.
Section 6.5.4 defines the range-based for
:
for ( for-range-declaration : expression ) statement
with the following desugaring:
{
auto && __range = range-init;
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}
where range-init
is just ( expression )
, and at least for class types, begin-expr
is either __range.begin()
or begin(__range)
, etc.
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.
Yes, it's perfectly safe.
From [class.temporary]/4-5:
There are two contexts in which temporaries are destroyed at a different point than the end of the fullexpression. The first context is when a default constructor is called [...]
The second context is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except:
- 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 [...]
None of those exceptions apply. The temporary thus persists for the lifetime of the reference, __range
, which is the entire loop.
这篇关于使用rvalue range-init的C ++ 11基于范围的for循环安全吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!