LONG STORY, SHORT
The compiler cannot extend the lifetime of the temporary involved in new A { "temporary " }
, because the A
created, and the temporary, has different storage durations.
A refence to what the Standard says can be found at the end of this post. The Standard explicitly says that the lifetime will not be extended, but it doesn't go into detail to why this is.
This post will try explain the reason in a way that is understandable for a broader audience, not only to the average language-lawyer https://stackoverflow.com/tags/language-lawyer/info.
介绍
在C++中有几种不同的类型储存期限一个对象可以有,其中有自动的- and 动态存储持续时间,简要解释如下:
自动存储时长
对象的存储自动存储时长将持续存在,直到创建它们的块退出。
动态存储时长
对象的存储动态存储持续时间将持续存在,直到明确声明应将其释放为止;换句话说,这种存储不受任何特定范围的限制。
- 动态创建的对象通过
operator new
正如暗示的那样,动态存储持续时间.
存储将持续存在,直到匹配的调用operator delete
已经做了。
聚合初始化自动存储时长
如上一节所述,临时有自动存储时长.
如果我们构造一个总计的 with 自动存储时长,这也将具有绑定到当前范围的存储;这意味着暂时的可以很容易地扩展以匹配总计的.
Note: We can imagine them living in the same "box", and at the end of the scope we discard this box, which is fine; neither the temporary, nor the aggregate, will outlive the lifetime of the box.
我们的实施 (A)
struct A { std::string const& ref; };
void func () {
A x { {"hello world"} };
}
幕后花絮 (A)
既然两者x
,以及临时的,有自动存储时长,编译器可以将函数实现为以下语义等效的代码片段:
void __func () {
std::string __unnamed_temporary { "hello world" };
A x { __unnamed_temporary };
}
Note: Both the temporary and the aggregate has their lifetime bound to the current scope, awesome!
聚合初始化动态存储持续时间
我们的实施 (B)
struct A { std::string const& ref; };
A* gunc () {
A * ptr = new A { { "hello world" } };
return ptr;
}
int main () {
A * p = gunc ();
std::cout << p->ref << std::endl; // DANGER, WILL ROBINSON!
delete p;
}
在前面的章节中已经指出,临时变量已经自动存储时长,这意味着我们暂时的、必然的A::ref
,将在驻留在当前范围内的存储上构建。
幕后花絮 (B)
语义上等价gunc
可以看成下面的实现:
A* gunc () {
A __unnamed_temporary { "hello world " };
A * ptr = new A { __unnamed_temporary }; // (1)
return ptr;
}
你也在想,不是吗?
我们不再能够延长临时的生命周期来匹配A
创建于动态存储持续时间, at (1).
问题是自动存储__unnamed_temporary
我们一回来就会消失gunc
,有效地杀死了我们的临时。
动态创建的A
然而仍然存在,给我们留下了一个悬而未决的参考main
.
结论
编译器无法延长通过创建对象时涉及的任何临时对象的生命周期新的初始化器因为newed 对象和临时对象将具有不同的存储持续时间。
标准是什么(n3797 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.pdf) say?
12.2p5
临时对象 [class.temporary]
引用绑定到的临时对象或引用绑定到的子对象的完整对象的临时对象在引用的生命周期内持续存在,但以下情况除外:
...
- 临时绑定到 a 中的引用新的初始化器(5.3.4) 一直持续到包含以下内容的完整表达式完成新的初始化器.
[ Note:这可能会引入悬空引用,并且鼓励实现在这种情况下发出警告。 --end note ]