访问用户定义的析构函数已启动但未完成的对象真的是UB吗?

问题描述

问题是由 a discussion on Reddit 引起的,一位用户告诉我,引用了标准关于对象生命周期的规则:

我很确定在对象被破坏时访问对象在技术上是 UB。

例如,我依赖于管理后台线程的类;我让他们的析构函数通知线程退出并等待它退出,并且该线程可以访问该对象。我需要重构我的代码吗?

解决方法

不,它定义明确。

如果 UB 在其析构函数执行时访问该对象,则该析构函数本身将无法对自己的对象执行任何操作。 ?


在您的析构函数执行期间:

  • 基地尚未被摧毁
  • “当前”对象本身还没有被破坏(也没有它的成员)
  • 一些资源可能已经被释放,如果你已经在析构函数中释放了
  • 派生的子对象已被破坏
    • 虚拟函数调用将安全地引用“当前”对象,而不是这些现已失效的派生子对象
    • dynamic_casttypeid 会做同样的事情
    • 但是,您不能使用 Derived* 执行任何这些操作!通过 Base*Current* 很好

这些规则中的大部分都包含在 [class.cdtor] 中。


虽然对象的生命周期确实在技术上以析构函数“调用”的开始结束,但此时您处于一种炼狱中,其中 [class.cdtor] 接管列出的规则以上:

[basic.life/7][..] 在一个对象的生命周期结束之后,在该对象占用的存储空间被重用或释放之前,任何引用原始对象的泛左值都可以可以使用,但只能以有限的方式使用。对于正在构建或销毁的对象,请参阅 [class.cdtor]。 [..]

这可能是一种容易出错且令人困惑的模式,但它本质上并非不正确。对于您的特定用例,我什至将其称为合理的常规。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...