【问题标题】:Lifetime of object is over before destructor is called?在调用析构函数之前对象的生命周期已经结束?
【发布时间】:2018-12-06 05:33:42
【问题描述】:

我不明白:

3.8/1 “T 类型对象的生命周期在以下情况下结束: — 如果 T 是具有非平凡析构函数 (12.4) 的类类型,则析构函数调用 开始,或者——对象占用的存储空间被重用或者 释放。”

如果生命周期在析构函数开始之前就结束了,这是否意味着访问析构函数中的成员是未定义的行为?

我也看到了这句话:

12.7 “对于具有非平凡析构函数的对象,在析构函数之后引用该对象的任何非静态成员或基类 完成执行会导致未定义的行为。”

但它并不清楚在析构函数期间允许什么。

【问题讨论】:

  • (出于某种原因,我认为这是重复的,但我找不到并且忘记了答案)
  • 12.7 并没有谈论你可以在析构函数中做什么,而是谈论在析构函数执行结束后会发生什么。
  • 您应该将此问题提交给 C++ 委员会。

标签: c++ destructor language-lawyer object-lifetime


【解决方案1】:

如果生命周期在析构函数开始之前就结束了,这是否意味着访问析构函数中的成员是未定义的行为?

希望不会:

来自 N3242 构造和销毁 [class.cdtor] /3

要形成一个指向对象 obj 的直接非静态成员(或访问其值)的指针,obj 的构造应该已经开始并且它的销毁应该没有完成,否则指针值的计算(或访问成员值)会导致未定义的行为。

【讨论】:

  • 这个答案是绝对错误的!然而却成功获得了 6 票。所以不工作。
  • @DavidRodríguez-dribeas 答案没有回答语言律师的问题,但非常清楚地证明了一些事情。
  • 答案是正确的,因为它说不,这至少不是 UB。而且它没有说任何不正确的东西,与这里的其他答案相比,这使它成为一个非常好的答案。
【解决方案2】:

对象的“生命周期”与对象的消费者相关,而不是对象本身。因此,一旦销毁开始,消费类不应尝试访问对象的成员。

【讨论】:

  • 消费对象是什么意思?
  • 任何使用目标类的对象。如果你编写一个使用字符串的类,那么你的类就是字符串的消费者。
  • “消费者”更常用的术语是“客户”。
  • 这是不正确的。生命周期与对象本身有关;例如它与如何从析构函数中解析虚函数有关。 “生命周期”是标准中具有特定含义和含义的特定术语,并不意味着“一旦开始销毁,消费类不应尝试访问对象的成员”。 如果类支持它,可以在析构函数正在进行时调用方法。我建议不要假设一个类支持它,除非特别记录!
  • 3.8 谈到“终身”。它指的是 12.7,它讨论了在对象的生命周期之外可以做什么和不能做什么。你在那里看到支持这个答案的东西吗? (您应该删除此答案,它是这里的最佳答案,但会提供误导性信息!)
【解决方案3】:

不,没有问题:

成员对象在构造函数主体运行之前激活,并且在析构函数完成之前它们一直保持激活状态。因此,可以在构造函数和析构函数中引用成员对象。

对象自身直到它自己的构造函数完成后才会活跃,并且一旦它的析构函数开始执行它就会死掉。但这只是外界所关心的。构造函数和析构函数仍然可以引用成员对象。

【讨论】:

  • 这是否意味着这将是无效的?:constructor() { outside_function(this); }(也可以是析构函数)
  • @Pubby:在构造函数和析构函数中使用this 时必须非常小心,因为它不指向活动对象。基本上,“不要使用它”适用。存储指针很好,但引用可能的对象不是。
  • 但是不使用this(假设它是隐式添加的)如何访问成员? constructor() { this->x = 0; this->mfun(); }
  • @Pubby 在构造函数中也有一些特殊规则——因为实例还没有“完全活跃”——例如, this->mfun() 中的 mfun() 不能虚拟的。
  • @Pubby:构造函数可以引用成员对象(因此“使用this”,如果你愿意的话)。构造函数不能调用外部函数foo(*this),它需要一个(完全构造的)对象。
【解决方案4】:

“终生”不是这个意思。它是标准中精确定义的术语,具有多种含义,但它可能没有您想象的所有含义。成员在构造和销毁时仍然可以使用,外部代码可以调用成员函数等。

诚然,客户端代码与析构函数同时调用成员函数有点奇怪,但并非闻所未闻,当然也不是语言不允许的。特别是,std::condition_variable 明确允许在对condition_variable::wait() 进行未完成的调用时调用析构函数。它只禁止在析构函数启动后new调用wait()

【讨论】:

    猜你喜欢
    • 2020-11-16
    • 2021-08-04
    • 2014-12-06
    • 2016-03-03
    • 2013-08-22
    • 2021-07-04
    • 2020-06-23
    • 1970-01-01
    相关资源
    最近更新 更多