c++ - 使用 std::launder 从指向非事件对象的指针获取指向事件对象成员的指针?

标签 c++ pointers language-lawyer c++17 unions

这个问题跟在这个 one 之后

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

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?
    }
  };

如果 short_str 不是事件成员,则在没有 std::launder 的情况下取消引用指针将是 UB。让我们考虑一下 ABI 已明确指定,并且我们知道 size_r[7] 与 short_str[15] 位于同一地址。当 short_str 不是 union 体的活跃成员时,std::launder(short_str+15) 是否返回指向 size_r[7] 的指针?


注意:我认为是这样,因为[ptr.launder]/3

A byte of storage is reachable through a pointer value that points to an object Y if it is within the storage occupied by Y, an object that is pointer-interconvertible with Y, or the immediately-enclosing array object if Y is an array element.

最佳答案

Let's consider that the ABI is well specified and that we know that size_r[7] is at the same address as short_str[15]

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

编译器可以自由保证

Sso.short_str[15]

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

或者不提供该保证是自由的。

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

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

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

你所做的不是那个。如果您在 参与时获取了 &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::launder。中间的某个地方需要 std::launder

关于c++ - 使用 std::launder 从指向非事件对象的指针获取指向事件对象成员的指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48189026/

相关文章:

c++ - 赋值给整型指针地址的 Char 指针地址

c - 带有指针变量的地址数组

c++ - 哪个版本的 C++ 标准允许重用先前由具有 const 或引用成员的类的对象占用的存储空间?

c++ - Lambda 作为模板变量

c++ - 结构未完成排序

c++ - GNU Radio general_work()函数

c++ - 如何使用 Eclipse for mac 编译和运行 C++ 程序?

c - 硬编码指针值

c++ - 在运算符重载中使用可变参数模板是否合法?

c++ - 努力使用链表实现 Set