对象生存期的结束与它不存在之间的关系是什么? 对象创建在哪里?指针有效性生命不存在

如何解决对象生存期的结束与它不存在之间的关系是什么? 对象创建在哪里?指针有效性生命不存在

在下面的简短示例中,指针f指向的对象或刚好从main返回之前指向的对象可以怎么说?

#include <vector>

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

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

我相信foo不再指向f所指向的对象。我收到很多评论,认为这可能不正确,相反,可能有一个对象foo处于被破坏,无效或无效的状态。

对于存在被明确销毁但其存储仍然有效的对象,语言标准怎么说?

换句话说,可以合理地说f上还有一个对象不在其生存期内吗?是否存在这样的事物,那就是它的生命周期不是没有开始,没有开始构造并且没有被破坏?


编辑:

很明显,一个对象可以在其生命周期中不存在。在建造和销毁过程中,有一个物体,其寿命尚未开始或已经结束。来自https://timsong-cpp.github.io/cppwp/intro.object#1

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

但是在f->~foo();指向的对象之后,f指向的对象(被称为o)没有被构造,它的生命周期也没有,也没有被破坏。我对本节的理解是,o不能再占用存储空间,因为它不在任何列举的情况下。似乎这意味着不再有o,也不再有指向o的指针。矛盾的是,如果您有一个指向o的指针,则该指针将指向o无法占据的存储空间。


编辑2:

如果没有对象了,那么foo有什么样的价值?似乎唯一可能的合理值是指向对象的指针,这将与该语句相矛盾。参见this question

解决方法

在C ++中,对象本质上是永恒的。语言中没有什么可以使对象消失的。处于生存期之外的对象仍然是一个对象,仍在占用存储空间,并且该标准具有specific things,您可以使用指向超出其生存期的对象的指针/引用。

仅当不可能有有效的指针/引用时,该对象才真正消失。当该对象占用的存储空间结束其存储持续时间时,就会发生这种情况。指向超出其持续时间的存储的指针是无效的指针,即使该地址本身以后再次变得有效,也是如此。

因此,通过调用析构函数而不是使用delete f(这也会取消分配存储空间),f仍指向类型为foo的对象,但是该对象位于其对象之外一生。


我上面陈述的理由基本上可以归结为对支持未创建对象概念所需的规定完全没有规定的标准。

对象创建在哪里?

该标准提供明确,明确的声明,说明对象何时会出现在一块存储中。 [intro.object]/1概述了引发对象创建的确切机制。

该标准提供了有关对象生命周期何时开始和结束的明确,明确的声明。 [basic.life]完全概述了这些内容,但是[basic.life] / 1特别说明了对象的生存期何时开始和结束。

标准不提供有关对象何时不存在的任何陈述(明确或其他方式)。该标准规定了对象的创建时间,生命周期的开始时间以及结束时间。但是从不会说它们何时停止存在于某个存储中。

还讨论了以下形式的声明:

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

添加了重点。

使用过去时表示对象不再位于该存储中。但是什么时候该物体停止停在那里?没有 clear 声明是什么原因导致的。除此之外,在这里使用过去时就没关系了。

如果您不能指出何时停止在那里的声明,那么您绝对可以说的是,标准中有几个地方可以清除措辞。并不能消除标准没有说明何时对象停止存在的明确事实。

指针有效性

但是它确实说明了何时无法再访问对象。

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

[basic.compound]/3概述了指针可以具有的状态。指针可以处于以下四种状态之一:

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

没有指向没有对象的指针的余量。允许使用“无效的指针值”,但是指针仅在the storage duration for the storage they point into ends时变为无效:

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

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

这正是标准要支持不再存在的对象的概念所需要的语句。

但是没有这样的陈述。

[basic.life]确实有一些语句,这些语句解决了可以使用指向超出其生命周期的对象的指针的有限方式。但请注意其使用的特定措辞:

有关正在构造或破坏的对象,请参见[class.cdtor]。否则,此类指针将引用已分配的存储([basic.stc.dynamic.deallocation]),并且使用该指针时,就像该指针的类型为void *一样,都是定义良好的。

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

也就是说,没有“分配存储的指针”之类的东西。存在“指向对象生命周期之外的指针,其指针值可用于引用分配的存储”。但是仍然是“指向对象的指针”。

生命不存在

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

实际上,如果结束对象的生存期意味着该对象不存在,则对象模型的复杂程度将大大降低。 [basic.life]的大多数内容都是关于在对象的生存期之外,使用特定的方法来使用对象的名称或指向该对象的指针/引用。如果对象本身不存在,我们就不需要那种东西。

有关此事的讨论中提到的是:

我相信提及寿命终止对象是为了说明正在构造的对象和正在破坏的对象。

如果是这样,[basic.life]/8 talking about with this statement是什么:

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

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

仅当那些对象在其生命周期之外继续存在时,此段落才有意义。不,它不仅在构造函数/析构函数中;本节中的示例清楚地表明了这一点:

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

operator=确实调用了析构函数的同时,析构函数在使用this指针之前完成了 。因此,[class.cdtor]的特殊规定在创建新对象时不适用于this。因此,新对象是在对旧对象的析构函数调用的外部中创建的。

因此,很明显,对象的“生命周期之外”规则旨在始终有效。这不仅仅是构造函数/析构函数的规定(如果有的话,它将明确地指出这一点)。这意味着在创建新对象之前,名称/指针/引用仍必须在其生命周期之外命名/指向/引用对象。

要做到这一点,它们命名/指向/引用的对象仍然必须存在

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?