使用带有右值范围初始化的 C++11 基于范围的 for 循环是否安全? [英] Is it safe to use a C++11 range-based for-loop with an rvalue range-init?

查看:21
本文介绍了使用带有右值范围初始化的 C++11 基于范围的 for 循环是否安全?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个按值返回 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:

在两种情况下,临时对象在与完整表达式结束不同的点被销毁.第一个上下文是调用默认构造函数时 [...]

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:

  • 临时绑定到构造函数的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 循环是否安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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