在调用析构函数之前对象的生命周期已经结束?
Posted
技术标签:
【中文标题】在调用析构函数之前对象的生命周期已经结束?【英文标题】:Lifetime of object is over before destructor is called? 【发布时间】:2012-01-26 13:01:35 【问题描述】:我不明白:
3.8/1 “T 类型对象的生命周期在以下情况下结束: — 如果 T 是具有非平凡析构函数 (12.4) 的类类型,则析构函数调用 开始,或者——对象占用的存储空间被重用或者 释放。”
如果生命周期在析构函数开始之前就结束了,这是否意味着访问析构函数中的成员是未定义的行为?
我也看到了这句话:
12.7 “对于具有非平凡析构函数的对象,在析构函数之后引用该对象的任何非静态成员或基类 完成执行会导致未定义的行为。”
但它并不清楚在析构函数期间允许什么。
【问题讨论】:
(出于某种原因,我认为这是重复的,但我找不到并且忘记了答案) 12.7 并没有谈论你可以在析构函数中做什么,而是谈论在析构函数执行结束后会发生什么。 您应该将此问题提交给 C++ 委员会。 【参考方案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()
。
【讨论】:
以上是关于在调用析构函数之前对象的生命周期已经结束?的主要内容,如果未能解决你的问题,请参考以下文章