我在聊天中看到了以下示例:
#include <iostream>
struct foo { ~foo() { std::cout << "destroying!\n"; } };
const foo& func(const foo& a, const foo&) { return a; }
int main()
{
foo x;
const foo& y = func(foo(), x);
std::cout << "main\n";
}
destroying!
main
destroying!
它似乎表明foo
临时的生命周期未扩展到整个main
,即使它绑定到该范围内的ref-to - const
。
据推测,终身延期只能“工作一次”;也就是说,它是在func
的参数初始化时应用的,但不会通过连续的绑定传递。
我的解释是否正确?如果是这样(并且如果任何单个段落直接适用),那么定义此行为的标准措辞是什么?
答案 0 :(得分:8)
你几乎是对的。这种行为实际上来自函数调用,而不是因为任何类型的“仅一次工作”规则。
以下是整个终身延伸“功能”的措辞,相关规则以粗体强调:
[C++11: 12.2/5]:
[..] 引用绑定的临时对象或绑定引用的子对象的完整对象的临时对象的生命周期仍然存在参考除:
- [..]
- 函数调用(5.2.2)中与引用参数的临时绑定一直持续到包含该调用的完整表达式完成为止。
- [..]
答案 1 :(得分:7)
这是两个问题报告的主题,http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1299和http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1568。
以前的问题报告,我是其中的记者,旨在涵盖所有这些情况,其中引用绑定到临时对象,但不打算延长寿命。问题正文中的描述仅提到prvalues与临时表达式混淆(实际上决定了他们评估的生命周期是否延长)。但是lvalue和xvalues同样在标准中与这些混淆。在static_cast
的上下文中发生的示例是问题编号#1568(其中使用“临时变量”进一步混淆了该问题)。
实际上,这是:
在函数调用(5.2.2)中对引用参数的临时绑定一直持续到包含该调用的完整表达式完成为止。
与同一段落中的其他规则相矛盾。因为临时绑定到两个函数调用中的引用参数和本地自动引用变量。
答案 2 :(得分:3)
这里适用的规则是常识。标准是 措辞不好,事实上确实如此。但是没有 实现它的实用方法。
答案 3 :(得分:1)
可能我有点慢但是对于我来说,通过阅读其他答案并不清楚这个问题的解决方案是什么。因此,我修改了显示的代码,并希望总结其他代码:答案是,如果您访问y
,则会获得未定义的行为!
运行此代码:
struct foo {
int id;
foo(int id) : id(id) { std::cout << "ctor " << id << std::endl; };
~foo() { std::cout << "dtor " << id << std::endl; }
};
const foo& func(const foo& a, const foo&) { return a; }
int main(int argc, char** argv) {
foo x(1);
const foo& y = func(foo(2), x);
std::cout << "main " << y.id << std::endl;
return 0;
}
我的输出是:
ctor 1
ctor 2
dtor 2
main 2
dtor 1
但是行main 2
是未定义的行为。