基于范围的 for 循环中 range-init 的生命周期是多少?

问题描述 投票:0回答:2

在最新的 C++ 标准中,它意味着:

for (foo : bar)
    baz;

相当于:

{
    auto && r = bar;
    for ( auto it = r.begin(), end = r.end(); it != end; ++it )
    {
        foo = *it;
        baz;
    }
}

当上面的bar是一个返回集合的函数调用时,eg:

vector<string> boo();

for (auto bo : boo())
    ...

这行不就变成:

auto&& r = boo();
...

因此

boo()
的临时返回值在语句
auto&& r = boo()
结束时被销毁,然后r在循环入口处成为悬挂引用。这个推理正确吗?如果没有,为什么不呢?

c++ for-loop c++11 language-lawyer lifetime
2个回答
24
投票

这个推理正确吗?如果没有,为什么不呢?

到目前为止都是正确的:

因此 boo() 的临时返回值在语句“auto&&r=boo()”末尾被销毁 [...]

将临时对象绑定到引用可以将其生命周期延长为引用的生命周期。因此临时对象会持续整个循环(这也是为什么在整个构造周围有一组额外的

{}
:以正确限制该临时对象的生命周期)。

这是根据 C++ 标准第 12.2 节第 5 段的规定:

第二个上下文是引用绑定到临时对象时。这 引用绑定到的临时对象或作为引用的临时对象 引用绑定到的子对象的完整对象 在引用的生命周期内持续存在,除了:

[此处不适用的各种例外情况]

这是一个有趣的属性,允许滥用 ranged-for 循环来处理非范围的事情:http://ideone.com/QAXNf


9
投票

推理不正确,因为

boo
按值返回临时对象。将此临时对象绑定到引用意味着临时对象的生命周期会延长。标准报价(§ 12.2/5):

[…] 引用所绑定的临时对象或作为引用所绑定的子对象的完整对象的临时对象在引用的生命周期内持续存在 […]

如果

boo
返回引用,则推理是正确的。返回对临时对象的引用的表达式的示例是
string("a") += string("b")
;在基于范围的
for
循环中使用此值会导致未定义的行为。

© www.soinside.com 2019 - 2024. All rights reserved.