使用std :: launder从指向非活动对象的指针获取指向活动对象成员的指针?

Oli*_*liv 10 c++ pointers unions language-lawyer c++17

这个问题followes这一个

我们来考虑这个示例代码:

struct sso
  {
  union{
    struct {
      char* ptr;
      char size_r[8];
      } large_str;
    char short_str[16];
    };

  bool is_short_str() const{
    return *std::launder(short_str+15)=='\0'; //UB?
    }
  };
Run Code Online (Sandbox Code Playgroud)

如果short_str不是取消引用指针的活动成员而std::launder不是UB.让我们考虑ABI已经明确指定,并且我们知道size_r [7]与short_str [15]位于同一地址.并std::launder(short_str+15)返回一个指针size_r[7]的时候short_str是不是工会的活跃成员?


Nota:我认为情况就是这样,因为[ptr.launder]/3

如果对象Y位于Y所占用的存储区内,则指向存储的字节可以到达,如果Y是指针可互换的对象,则指向对象Y,或者如果Y是数组元素,则指向立即封闭的数组对象.

Yak*_*ont 3

让我们考虑 ABI 已明确指定,并且我们知道 size_r[7] 与 Short_str[15] 位于同一地址

这完全取决于该保证的确切含义。

编译器可以自由地保证

Sso.short_str[15]
Run Code Online (Sandbox Code Playgroud)

即使当前处于活动状态,也可以访问和修改所有内容Sso.large_str,并准确获得您期望的语义。

或者不提供这种保证也是自由的。

对于格式错误或表现出未定义行为的行为或程序没有任何限制。

由于那里没有对象,因此&Sso.short_str[15]指针不能与任何东西相互转换。不存在的对象不具有与另一个对象“相同的地址”。

Launder 是根据指向预先存在的对象的指针来定义的。然后该指针被销毁,并创建一个具有相同地址的新对象(这是明确定义的)。 std::launderthen 让您获取指向不再存在的对象的指针并获取指向现有对象的指针。

你所做的不是那样的。如果你&short_str[15]在它参与时获取,你就会有一个指向一个对象的指针。ABI 可以说这与 位于同一地址size_r[7]。现在std::launder将处于有效性范围内。

但编译器可以更进一步,定义short_str[15]引用同一个对象,size_r[7]即使它不活动。

short_str[15]我能看到的与你的内容一致的最弱的 ABI 保证只有在你获取了它活跃时的地址时才有效;稍后,您将启用large_str,然后您可以从&short_str[15]到进行清洗&size_r[7]。与您的声明一致的最强 ABI 保证使得调用不需要std::launderstd::launder需要在中间的某个地方。