对象生命周期的结束和它不再存在之间有什么关系?

2024-06-22

在下面的简短示例中,关于指针对象可以说些什么f指向或用于指向返回之前main?

#include <vector>

struct foo {
    std::vector<int> m;
};

int main()
{
    auto f = new foo;
    f->~foo();
}

我相信不再有一个物体foo where f用来指点。我收到了很多评论,认为这可能不正确,而是可能有一个对象foo处于毁坏、死亡或其他无效状态。

对于显式销毁但其存储仍然有效的对象的存在,语言标准有什么规定?

换句话说,是否可以合理地说,在f那超出了它的生命周期?是否存在这样的事情:一个对象不在其生命周期内,未开始构造且未被销毁?


Edit :

很明显,一个对象在不在其生命周期内时仍然可以存在。在构造和销毁期间,有一个对象,其生命周期尚未开始或已经结束。从https://timsong-cpp.github.io/cppwp/intro.object#1 https://timsong-cpp.github.io/cppwp/intro.object#1 :

[...] 对象在其构造期间 ([class.cdtor])、整个生命周期以及销毁期间 ([class.cdtor]) 占用一个存储区域。 [...]

但是之后f->~foo();所指向的对象f(我们称之为o) 没有被构造,它不在它的生命周期内,也没有被破坏。我对本节的阅读是o无法再占用存储空间,因为它不处于任何枚举的情况。这似乎意味着没有o不再有一个指针可以指向o不再了。通过矛盾,如果你有一个指向o那么该指针将指向存储o不能占据。


Edit 2 :

如果不再有对象,那么什么样的值会起作用foo有?看起来它唯一可能具有的合理值是指向对象的指针,这与该声明相矛盾。看这个问题 https://stackoverflow.com/questions/63770160/what-is-the-value-of-a-pointer-after-an-explicit-destructor-call.


在 C++ 中,对象本质上是eternal。语言中没有任何东西可以使物体消失。超出其生命周期的对象仍然是一个对象,它仍然占用存储空间,并且标准有具体的事情 https://timsong-cpp.github.io/cppwp/n4659/basic.life#6您可以使用指向超出其生命周期的对象的指针/引用来执行此操作。

只有当不可能有有效的指针/引用时,对象才会真正消失。当该对象占用的存储结束其存储持续时间时,就会发生这种情况。超过其持续时间的指向存储的指针是无效指针,even if地址本身稍后再次有效。

所以通过调用析构函数而不是使用delete f(这也会释放存储空间),f仍然指向类型的对象foo,但该对象已超出其生命周期。


我上述陈述的理由基本上可以归结为以下标准:none支持非创建对象概念所需的规定。

对象非创造在哪里?

该标准提供了关于对象何时存在于存储中的清晰、明确的声明。[介绍对象]/1 https://timsong-cpp.github.io/cppwp/n4659/intro.object#1概述了激发对象创建的确切机制。

该标准提供了关于对象生命周期何时开始和结束的清晰、明确的声明。[基本生活] https://timsong-cpp.github.io/cppwp/n4659/basic.life其完整概述了这些内容,但 [basic.life]/1 特别解释了对象的生命周期何时开始和结束。

标准does not提供有关对象何时不再存在的任何声明(明确或其他)exists。该标准规定了对象何时创建、其生命周期何时开始以及何时结束。但never它是否说明它们何时停止存在于某个存储空间中。

还对以下形式的陈述进行了讨论:

表示对象所在存储位置地址的任何指针或位于可以使用,但只能以有限的方式使用。

添加了强调。

使用过去时表明该对象不再位于该存储中。但是这个物体什么时候不再位于那里了呢?没有clear关于到底是什么导致了这种情况发生的声明。如果没有这一点,这里使用过去时就无关紧要了。

如果您无法指出有关它何时停止存在的声明,那么您最多可以说的是标准中有几个地方的措辞可以清理。它并没有消除一个明显的事实,即该标准没有说明对象何时停止存在。

指针有效性

但它确实说明了对象何时不再可访问。

为了使对象停止存在,标准必须考虑当这些对象不再存在时指向这些对象的指针。毕竟,如果一个指针指向一个对象,那么该对象必须仍然存在, right?

[碱性化合物]/3 https://timsong-cpp.github.io/cppwp/n4659/basic.compound#3概述了指针可以具有的状态。指针可以处于四种状态之一:

  • 指向对象或函数的指针(该指针被称为指向对象或函数),或者
  • 超过对象末尾的指针 ([expr.add]),或
  • 该类型的空指针值 ([conv.ptr]),或者
  • 无效的指针值。

不允许指针指向任何对象。允许“无效指针值”,但指针仅在以下情况下才变得无效:它们指向的存储的存储持续时间 https://timsong-cpp.github.io/cppwp/n4659/basic.stc#4:

当到达存储区域的持续时间结束时,表示该存储区域的任何部分的地址的所有指针的值变成无效指针值。

请注意,此语句意味着所有指向此类对象的指针不再处于“指向对象的指针”状态,而是进入“无效指针”状态。因此,此类存储中的对象(无论是在其生命周期内还是在其生命周期外)都不再可访问。

这正是标准需要存在的那种声明来支持不再存在的对象的概念。

但不存在这样的说法。

[basic.life] 确实有几个语句,这些语句解决了可以使用指向生命周期之外的对象的指针的有限方式。但请注意它使用的具体措辞:

对于正在构造或销毁的对象,请参阅[class.cdtor]。否则,这样的指针引用分配的存储([basic.stc.dynamic.deallocation]),并且使用该指针就好像该指针是 void* 类型一样,是明确定义的。

It never表示指针“指向”分配的存储空间。它永远不会撤消 [basic.compound]/3 关于指针类型的声明。指针仍然是一个指向对象的指针;只是指针“指的是分配的存储空间”。并且该指针可以用作void*.

也就是说,不存在“指向已分配存储空间的指针”这样的东西。有一个“指向生命周期之外的对象的指针,其指针值可用于引用分配的存储空间”。但仍然是“指向对象的指针”。

一生不等于存在

对象必须存在才能有生命周期。该标准明确了这一点。然而,该标准在任何时候都没有将对象的存在与其生命周期联系起来。

事实上,如果对象生命周期的结束意味着该对象不存在,则对象模型会简单得多。 [basic.life] 的大部分内容都是关于在该对象的生命周期之外使用对象名称或指向该对象的指针/引用的特定方式。如果对象本身不存在,我们就不需要这类东西。

关于此事的讨论是这样的:

我相信提到生命周期外的对象是为了解释正在构造的对象和正在被破坏的对象。

如果这是真的,那是什么[basic.life]/8 用这个语句来谈论 https://timsong-cpp.github.io/cppwp/n4659/basic.life#8:

如果一个对象的生命周期结束后,在该对象占用的存储空间被重用或释放之前,在原对象占用的存储位置上创建一个新的对象,一个指向原对象的指针,一个指向该对象的引用引用原始对象,或原始对象的名称

如果当对象的生命周期结束时,指向原始对象的指针变成指向已分配内存的指针,那么为什么这个语句谈论指向原始对象的指针呢?指针不能指向不存在的对象,因为它们不存在.

只有当这些物体在其生命周期之外继续存在时,这段话才有意义。不,这不仅仅涉及构造函数/析构函数;还涉及构造函数/析构函数。本节中的示例非常清楚地表明了这一点:

struct C {
  int i;
  void f();
  const C& operator=( const C& );
};

const C& C::operator=( const C& other) {
  if ( this != &other ) {
    this->~C();                 // lifetime of *this ends
    new (this) C(other);        // new object of type C created
    f();                        // well-defined
  }
  return *this;
}

C c1;
C c2;
c1 = c2;                        // well-defined
c1.f();                         // well-defined; c1 refers to a new object of type C

While operator=确实调用析构函数,该析构函数完成before the this使用指针。因此,特别规定[类.cdtor] https://timsong-cpp.github.io/cppwp/n4659/class.cdtor不适用于this此时新对象已创建。这样新的对象就被创建了outside析构函数调用旧的析构函数。

所以很明显,对象的“在其生命周期之外”规则的目的是always工作。它不仅仅是对构造函数/析构函数的规定(如果是的话,它会明确地指出这一点)。这意味着名称/指针/引用必须在其生命周期之外仍然命名/指向/引用对象,直到创建新对象。

为了实现这一点,他们命名/指向/引用的对象必须仍然存在.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对象生命周期的结束和它不再存在之间有什么关系? 的相关文章

随机推荐

  • 如何检查Canvas中的两个图形(线)是否发生碰撞?

    所以我一直在开发一款跑步火柴人游戏 不幸的是 我遇到了这个问题 我似乎无法弄清楚 如果名为障碍物的绘图穿过我的火柴人 我希望出现警报并说 游戏结束 然而 如果我的火柴人踢 他变成红色 并且障碍物接触到图纸的右脚 那么它会说 你赢了 任何帮助
  • VT100 ANSI 转义序列:获取屏幕尺寸、条件 ANSI

    当我在终端上调整大小时 它保持全屏 我想 有某种方法可以找出终端的屏幕尺寸 我怎样才能在 VT100 中做到这一点 使用 时 当我列出文件夹时 它会以蓝色显示文件夹 或者说不同的颜色 但是 如果将输出保存到文本文件 ls gt out tx
  • 如何根据发送者的身份使新消息显示在左侧/右侧? (无浮动)

    我正在尝试制作一个网页 根据用户 1 左文本区域 或用户 2 右文本区域 是否发送消息 黄色对话窗口中的消息显示在左侧或右侧 与消息在手机上的显示方式相同如今 通过发送消息的背景颜色可以区分消息的发送者 用户1为浅蓝色 用户2为紫色 我试图
  • 如何在同一个类(C++、MFC)中调用工作线程?

    这是我的代码 其中包含错误 void ClassA init HANDLE hThread data thread thread is an object of struct data hThread CreateThread NULL 0
  • 如何控制TextView何时将String发送到新行?

    当一个词出现在String from a TextView太大 无法与前面的单词放在同一行 它会跳到下一行 事实证明这非常有用 然而 这让我陷入了两难的境地 我的String出于我的特殊原因 需要在单词的每个字母之间有一个空格 并且在单词之
  • 当 Inno Setup 中的注册表值仅使用默认名称时,如何获取该值?

    我正在尝试使用 Inno Setup 的 Pascal 脚本从 Windows 注册表 本例中为 Google Sketchup 获取应用程序的安装目录 以便我可以在那里安装插件 该注册表项没有名称 在 Regedit 中只有 默认 我试过
  • Codeigniter result_array() 返回一行

    在我的表中 我有两行 但是当我print r the data该模型函数连接到它只返回数据库中的第二行 为什么 型号功能 function getAllUsers query this gt db gt get users foreach
  • 通过 GUI 将日期输入数据库,以便 FMDatabase 读取

    我有一组事件 在发布应用程序之前必须将其输入数据库 以便应用程序准备好从此数据库中读取数据 我看过一些类似这样的帖子 解释了如何将 NSDate 输入数据库以便可以读回 iPhone SQLite日期问题 https stackoverfl
  • 如何使用 WebApi2、OData 和 $expand 指定结果的形状

    当我将 OData 与特定的对象一起使用时 执行 AutoMapper 映射时遇到问题 select or expand values 使用 WebApi 操作 public IQueryable
  • 类型通过联合分配意味着什么?

    我正在读一篇文章 在 TypeScript 中 我们最强大的工具是条件类型 这是 因为他们有两个独特的能力 他们通过工会进行分配 它们使您能够使用 infer 关键字 在一般情况下以及在这种情况下 在工会上分配 意味着什么 期限分配性的指的
  • 使用 WebGL 的 iOS PhoneGap 应用

    PhoneGap 应用程序的 WebView 是哪个 是 Safari 移动版还是桌面版 是否可以在 PhoneGap 应用程序中使用 WebGL 如果没有 他们可以尝试将应用程序提交到 Apple Store 和 Android Stor
  • Bootstrap 3:如何获取文档的打印版本? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 有人有办法让 Bootstrap 3 文档像 getbootstrap com 网站上显示的那样打印吗 如果您尝试使用浏览器的 打印 按钮
  • 由于派生表,实体框架速度很慢

    我将 MySQL Connector Net 6 5 4 与 LINQ toEntity 一起使用 并且经常获得糟糕的查询性能 因为实体框架生成使用派生表的查询 这是我多次遇到的一个简化示例 在 C 中 我编写如下查询 var culver
  • 用于生成 4GB ISO 的构建系统的版本控制解决方案

    我有一个软件项目 在其构建的最后阶段 在创建所有 jar 文件和相关脚本 配置文件之后 我需要将其植入 CentOS ISO 中 该 ISO 具有一个 kickstart 配置文件 该文件运行一些安装后脚本并安装一些定制的 RPM 该项目位
  • MySQL 中的外键:错误 1005

    我对在 MySQL 中添加外键有点困惑 我想做的是引用学生主键 CREATE TABLE Enrolled sid CHAR 20 cid CHAR 20 grade CHAR 2 PRIMARY KEY sid cid FOREIGN K
  • 仅使用移位加法和减法的对数时间整数除法

    我被要求仅使用位移位 加法和减法来实现对数时间复杂度的整数除法 我可以看到如何处理 2 的幂的除数 但是如何处理奇数除数 以使时间保持对数 有可能吗 编辑 一种以非对数时间复杂度但仍然比线性更好的方法来完成它也将受到欢迎 Thanks 这就
  • Java MVC - 我在这里遗漏了什么吗? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 有没有办法手动推送 NewRelic 错误?

    在我们的 Rails 应用程序中 我们挽救了 ApplicationController 上的大多数异常以提供正确的 API 响应 但仍然希望使用 ErrorCollector 跟踪发生的错误 有没有办法手动向 NewRelic 发送错误
  • “丢失”jni.h 文件导致 JPostal 构建失败

    我想建设日本邮政 https github com openvenues jpostal building jpostal但发出命令后出现以下错误 gradlew assemble checking for gcj no checking
  • 对象生命周期的结束和它不再存在之间有什么关系?

    在下面的简短示例中 关于指针对象可以说些什么f指向或用于指向返回之前main include