使用rvalue range-init的C ++ 11基于范围的for循环安全吗? [英] Is it safe to use a C++11 range-based for-loop with an rvalue range-init?

查看:167

是,这是完全安全的。



从[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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆