Jam*_*ree 10 c++ temporary lifetime auto c++11
下面的代码说明了我的担忧:
#include <iostream>
struct O
{
~O()
{
std::cout << "~O()\n";
}
};
struct wrapper
{
O const& val;
~wrapper()
{
std::cout << "~wrapper()\n";
}
};
struct wrapperEx // with explicit ctor
{
O const& val;
explicit wrapperEx(O const& val)
: val(val)
{}
~wrapperEx()
{
std::cout << "~wrapperEx()\n";
}
};
template<class T>
T&& f(T&& t)
{
return std::forward<T>(t);
}
int main()
{
std::cout << "case 1-----------\n";
{
auto&& a = wrapper{O()};
std::cout << "end-scope\n";
}
std::cout << "case 2-----------\n";
{
auto a = wrapper{O()};
std::cout << "end-scope\n";
}
std::cout << "case 3-----------\n";
{
auto&& a = wrapper{f(O())};
std::cout << "end-scope\n";
}
std::cout << "case Ex-----------\n";
{
auto&& a = wrapperEx{O()};
std::cout << "end-scope\n";
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在这里看到它.
据说这auto&&
将延长临时物体的使用寿命,但我找不到这条规则的标准词,至少在N3690中没有.
最相关的可能是关于临时对象的第12.2.5节,但不完全是我正在寻找的内容.
那么,auto && life-time扩展规则是否适用于表达式中涉及的所有临时对象,或仅适用于最终结果?
更具体的是a.val
,在我们到达案例1的范围结束之前,保证有效(非悬空)?
编辑: 我更新了示例以显示更多案例(3&Ex).
你会看到,只有在案例1中,O的寿命才会延长.
与引用相同的方式const
:
const auto& a = wrapper{O()};
Run Code Online (Sandbox Code Playgroud)
要么
const wrapper& a = wrapper{O()};
Run Code Online (Sandbox Code Playgroud)
或者也
wrapper&& a = wrapper{O()};
Run Code Online (Sandbox Code Playgroud)
更具体的是
a.val
,在我们到达案例1的范围结束之前,保证有效(非悬空)?
是的.
这里几乎没有什么特别重要的auto
.它只是正确类型()的占位符,wrapper
由编译器推导出来.重点是临时绑定到引用的事实.
有关详细信息,请参阅我引用的"最重要的const"的候选人:
通常,临时对象仅持续到它出现的完整表达式的结尾.但是,C++故意指定将临时对象绑定到堆栈上对const的引用会延长临时对象到引用本身生命周期的生命周期
这篇文章是关于C++ 03但是参数仍然有效:临时可以绑定到引用const
(但不是对非引用const
).在C++ 11中,临时也可以绑定到右值引用.在这两种情况下,临时的生命周期都延长到参考的生命周期.
C++ 11标准的相关部分正是OP中提到的那些部分,即12.2 p4和p5:
4 - 有两种情境,其中临时表在与完整表达结束时不同的点被销毁.第一个背景是[...]
5 - 第二个上下文是指引用绑定到临时.[...]
(在这些行之后的子弹点中有一些例外.)
更新 :(关注texasbruce的评论.)
为什么原因O
的情况下,2具有寿命短是,我们有auto a = wrapper{O()};
(见,有没有&
在这里),然后临时的不绑定到一个参考.实际上,临时a
使用编译器生成的复制构造函数进行复制.因此,临时文件的生命周期不会扩展,并在其出现的完整表达式结束时死亡.
这个特定的例子存在危险,因为它wrapper::val
是一个参考.编译器生成的copy-constructor wrapper
将绑定a.val
到临时val
成员绑定的同一对象.此对象也是临时但类型O
.然后,当后者临时死亡时,我们~O()
在屏幕上看到并a.val
摇晃!
对比案例2:
std::cout << "case 3-----------\n";
{
O o;
auto a = wrapper{o};
std::cout << "end-scope\n";
}
Run Code Online (Sandbox Code Playgroud)
输出是(使用gcc编译时使用选项-fno-elide-constructors
)
case 3-----------
~wrapper()
end-scope
~wrapper()
~O()
Run Code Online (Sandbox Code Playgroud)
现在暂时wrapper
有其val
成员必然o
.请注意,这o
不是暂时的.正如我所说,a
是wrapper
临时的副本a.val
也是绑定的
o
.在范围结束之前临时wrapper
死亡,我们~wrapper()
在屏幕上看到第一个.
然后范围结束,我们得到end-scope
.现在,a
而且o
必须在施工相反的顺序被破坏,因此,我们看到~wrapper()
,当a
死了,最后~O()
当它的o
时候了.这表明a.val
不会摇摆不定.
(最后的评论:我曾经习惯于-fno-elide-constructors
阻止与复制构造相关的优化,这会使讨论变得复杂,但这是另一个故事.)
归档时间: |
|
查看次数: |
1017 次 |
最近记录: |