延长临时的生命周期,适用于块范围聚合,但不能通过“new”;为什么?

2024-03-20

Note: This question was originally asked as a comment https://stackoverflow.com/questions/23892018/extending-temporarys-lifetime-through-rvalue-data-member-works-with-aggregate/23965233#comment36922467_23965233 by Ryan Haining https://stackoverflow.com/users/1013719/ryan-haining on this answer https://stackoverflow.com/a/23965233/1090079.


struct A { std::string const& ref; };
// (1)

A a { "hello world" };              // temporary's lifetime is extended to that of `a`
std::cout << a.ref << std::endl;    // safe
// (2)

A * ptr = new A { "hello world" };  // lifetime of temporary not extended?
std::cout << ptr->ref << std::endl; // UB: dangling reference

Question

  • 为什么临时的寿命会延长(1),但不在(2)?

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 动态存储持续时间,简要解释如下:

自动存储时长

对象的存储自动存储时长将持续存在,直到创建它们的块退出。

  • 在块作用域中声明的对象具有自动存储时长(除非他们声明static or extern, 但不是register).

  • 根据定义,临时变量是在块作用域中声明的,因此它们也具有自动存储时长.


动态存储时长

对象的存储动态存储持续时间将持续存在,直到明确声明应将其释放为止;换句话说,这种存储不受任何特定范围的限制。

  • 动态创建的对象通过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 ]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

延长临时的生命周期,适用于块范围聚合,但不能通过“new”;为什么? 的相关文章

随机推荐

  • iOS 13中的prefersStatusBar隐藏问题

    大家好 我想隐藏我的状态栏 in a View Controller但它似乎不起作用 我使用了该功能 override var prefersStatusBarHidden Bool return true 我还设置了View contro
  • Parse Javascript SDK -- 将客户端 `user` 保存为服务器端 ` Parse.User.current()`

    我可能在概念上做错了事情 所以请告诉我我是否错了 我正在使用 Parse 的 Facebook 登录来登录用户客户端 然后我尝试发布这个user object到我的服务器 这样我就可以在服务器端拥有该用户对象 但我在文档中找不到与此相关的任
  • xcode swift 如何分割图像?

    我正在使用 Swift 2 0 我想将图像分割成多个部分 我知道这是重复的 但它们的语法很旧 我在更新时遇到问题 update Xcode 8 2 1 斯威夫特 3 0 2 您可以添加此扩展来分割图像 extension UIImage v
  • ng 升级命令将 cli 从 v7 升级到 v8 失败

    用于将 cli 版本从 v7 项目更新到 v8 的 ng Upgrade 命令失败 首先手动尝试升级 cli 也会失败 ng update angular cli 您的全局 Angular CLI 版本 8 0 1 高于您的本地版本 版本
  • sklearn RandomForestClassifier 与 auc 方法中 ROC-AUC 分数的差异

    我分别从 sklearn 的 RandomForestClassifier 和 roc curve auc 方法收到不同的 ROC AUC 分数 以下代码得到了 0 878 的 ROC AUC 即 gs best score def tra
  • 斜杠和 python cmd

    我正在尝试使用 cmd 模块来实现 python cmd 我想自动完成文件 所以我实现了一些方法 但是 我看到 complete put self text line begidx endidx 中的文本参数删除了所有 字符 任何人都知道为
  • 如何将 AsParallel 与 async 和 wait 关键字一起使用?

    我正在查看某人的异步示例代码 并注意到其实现方式存在一些问题 在查看代码时 我想知道使用并行方式循环列表是否比正常循环列表更有效 据我所知 性能上的差异非常小 两者都耗尽了每个处理器 并且完成时间都相同 这是第一种方法 var tasks
  • 启动 python windows 服务可执行文件时出错

    我正在尝试按照指示创建一个 python windows 服务 https www thepythoncorner com 2018 08 how to create a windows service in python https ww
  • 如何增加/减少 x 和 y 刻度标签的字体大小[重复]

    这个问题在这里已经有答案了 我似乎在弄清楚如何增加或减少fontsize使用时的 x 和 y 刻度标签matplotlib 我知道有set xticklabels labels fontdict None minor False kwarg
  • sqlalchemy 连接失败但 cx_oracle 成功

    我正在尝试用 Python 连接到 Oracle 服务器 我在 cx Oracle 中可以正常工作 但是当我尝试使用 sqlalchemy 连接时 它失败了 cx Oracle代码 import cx Oracle import panda
  • 我应该如何使用tiny_mce_popup.js 更新 TinyMCE 插件版本 4?

    TinyMCE4 文档目前很糟糕 我有一个与 Ruby on Rails 兼容的插入图像插件 但它依赖于已弃用的tiny mce popup js 没有关于我应该如何更新插件以规避该文件的使用的信息 TinyMCE 4 弃用旧版本file
  • 删除大文件后 git Push

    我不小心提交了 log test log 但从未推送过它 从那以后我做了一个 git rm 来摆脱它 但是当我尝试推送时 我仍然收到大量数据试图传输 git rm 不应该解决这个问题吗 如果没有 我该如何修复它 不要恢复提交然后推送 因为大
  • 使用数据库中的数据填充 IAuthSession

    因此 我根据此处的示例使用 ServiceStack 创建了一个自定义 CredentialsAuthProvider https github com ServiceStack ServiceStack wiki Authenticati
  • 通过 gganimate 制作动画条形图:view_follow 和 coord_flip 的冲突

    我想创建一个动画条形图gganim包裹 条形图的坐标应通过翻转coord flip 即水平条 和 x 轴应根据条的长度通过view follow 考虑以下示例数据 Create example data df lt data frame o
  • 错误“调用可以抛出,但未标记为‘try’并且错误未被处理”

    这段代码出现错误 调用可以抛出 但没有标记 try 并且错误不被处理 我使用的是 Xcode 7 1 最新的 beta 和 swift 2 0 func checkUserCredentials gt Bool PFUser logInWi
  • 具有多租户的 Spring Batch

    我们如何定义针对多个租户运行的 Spring 批处理作业 我已经设置为每晚针对一个数据库模式按顺序运行一系列作业 当前所有作业都从某个位置读取文件并插入到数据库 批处理配置非常基本 我在其中定义了数据源 事务管理器并将作业存储库映射到它 我
  • MongoDB 多个字段上的唯一索引

    我正在使用 MongoDb 数据库 我需要使多个字段唯一 我需要的是 MongoDb 检查是否组合多个字段的值是唯一的 让我们举一个我需要的例子 如果我在添加索引后按此顺序在数据库中添加以下内容 name paul age 21 name
  • scipy 中的复杂 ODE 系统

    我在求解光学布洛赫方程时遇到困难 该方程是具有复数值的一阶 ODE 系统 我发现 scipy 可以解决这样的系统 但是他们的网页提供的信息太少 我几乎无法理解 我有 8 个耦合一阶 ODE 我应该生成一个如下函数 def derv y co
  • 如何在Java中计算“时间之前”?

    在 Ruby on Rails 中 有一个功能允许您获取任何日期并打印出它是 多久以前 的 例如 8 minutes ago 8 hours ago 8 days ago 8 months ago 8 years ago 在 Java 中是
  • 延长临时的生命周期,适用于块范围聚合,但不能通过“new”;为什么?

    Note This question was originally asked as a comment https stackoverflow com questions 23892018 extending temporarys lif