手动结束基类子对象的生命周期将如何影响对完整对象的访问?

Lan*_*ern 7 c++ language-lawyer c++20

让我们首先考虑一段简单的示例代码:

struct Base { int b; };
struct Derived : Base { int d; };

int access_by_ptr() {
  auto *obj = new Derived{1, 2};
  static_cast<Base *>(obj)->~Base();
  return obj->d;  // #1
}

int access_by_ref() {
  auto &obj = *new Derived{1, 2};
  static_cast<Base &>(obj).~Base();
  return obj.d;  // #2
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,根据标准,#1和是#2明确定义的吗?

至于#1,根据[basic.life]/6,当一个对象的生命周期结束时,所有代表死亡对象地址的指针实际上都变得无效,并且只能以有限的方式使用,其中不包括类成员访问:

[basic.life]/6:在对象的生命周期开始之前,但在该对象将占用的存储已分配之后29,或者在对象的生命周期结束之后,在重用或释放该对象占用的存储之前,任何表示对象将位于或曾经位于的存储位置的地址的指针都可以使用,但只能以有限的方式使用

由于基本子对象的布局未指定,因此我们假设inBase中的子对象采用与 相同的地址,这在实际实现中通常采用。当此基子对象的生命周期结束时,只能以有限的方式使用,因为它表示的地址与子对象的地址相同。然后用于访问类成员,这是标准明确禁止的。所以我认为应该包含未定义的行为。*objaccess_by_ptr*objobjBaseobj#1

至于#2,根据[basic.life]/7,当一个对象的生命周期结束时,只有那些引用死亡对象的泛左值才会变得无效:

[basic.life]/7:同样,在对象的生命周期开始之前但在该对象将占用的存储空间已分配之后,或者在对象的生命周期结束之后且在该对象占用的存储空间被重用之前或释放时,任何引用原始对象的左值都可以使用,但只能以有限的方式使用

因此,在对象的子对象被销毁后, objin的引用access_by_ref不受影响,仍然引用该对象。所以我相信应该没问题。DerivedBase#2

我的理解正确吗?如果我的理解是正确的,那么在这种情况下引用和指针之间的区别看起来很微妙,这是故意的吗?