Is it safe to use a C++11 range-based for-loop with an rvalue range-init?(使用带有右值范围初始化的 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 循环是否安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:使用带有右值范围初始化的 C++11 基于范围的 for 循环是否安全?
基础教程推荐
- 为 C/C++ 中的项目的 makefile 生成依赖项 2022-01-01
- 如何“在 Finder 中显示"或“在资源管理器中显 2021-01-01
- 在 C++ 中循环遍历所有 Lua 全局变量 2021-01-01
- 为什么语句不能出现在命名空间范围内? 2021-01-01
- 使用从字符串中提取的参数调用函数 2022-01-01
- Windows Media Foundation 录制音频 2021-01-01
- 如何使图像调整大小以在 Qt 中缩放? 2021-01-01
- 从 std::cin 读取密码 2021-01-01
- 管理共享内存应该分配多少内存?(助推) 2022-12-07
- 如何在不破坏 vtbl 的情况下做相当于 memset(this, ...) 的操作? 2022-01-01