这个问题跟在这个 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/