C++ 在标准布局对象内执行指针运算(例如,使用offsetof)时,是否需要使用std::launder?
这个问题是对以下问题的后续行动: 年,CWG确认在标准布局对象内使用C++ 在标准布局对象内执行指针运算(例如,使用offsetof)时,是否需要使用std::launder?,c++,language-lawyer,c++17,offsetof,C++,Language Lawyer,C++17,Offsetof,这个问题是对以下问题的后续行动: 年,CWG确认在标准布局对象内使用无符号字符指针执行指针算法是合法的。这似乎意味着一些类似于链接问题中的代码应按预期工作: struct Foo { float x, y, z; }; Foo f; unsigned char *p = reinterpret_cast<unsigned char*>(&f) + offsetof(Foo, z); // (*) *reinterpret_cast<float*>(p)
无符号字符
指针执行指针算法是合法的。这似乎意味着一些类似于链接问题中的代码应按预期工作:
struct Foo {
float x, y, z;
};
Foo f;
unsigned char *p = reinterpret_cast<unsigned char*>(&f) + offsetof(Foo, z); // (*)
*reinterpret_cast<float*>(p) = 42.0f;
structfoo{
浮动x,y,z;
};
福福;
unsigned char*p=reinterpret_cast(&f)+offsetof(Foo,z);//(*)
*重新解释铸件(p)=42.0f;
(为了更加清晰,我将char
替换为unsigned char
。)
然而,C++17中的新变化似乎意味着该代码现在是UB,除非在这两个重新解释后都使用std::launder
。两种指针类型之间的重新解释转换
的结果相当于两种静态转换
s:第一种转换为cvvoid*
,第二种转换为目标指针类型。但是[expr.static.cast]/13意味着这将生成指向原始对象的指针,而不是指向目标类型的对象,因为Foo
类型的对象在其第一个字节处不可与无符号字符
对象进行指针互换,位于f.z
指针第一个字节的无符号字符
对象也不能与f.z
本身进行相互转换
我发现很难相信委员会打算做出改变,打破这个非常常见的习惯用法,使所有C++17之前的offsetof
用法都未定义。你的问题是:
在一个应用程序中执行指针算术时,是否需要使用std::launder
标准布局对象(例如,具有偏移)
没有
std::launder
在这种情况下不会改变任何东西,因此与所提供的示例无关(imo编辑launder排除问题或询问其他问题)
std::launder
通常仅在某些情况下需要(例如,由于const成员),在这些情况下,您以某种运行时方式(例如,通过放置新对象)更改(或创建)基础对象。助记符:对象是“脏的”,需要对其进行std::launder
'
仅使用标准布局类型不会导致需要使用std::launder的情况。@Artyer严格别名不是这里的问题。严格的别名规则在C++17之前就存在,与之无关。@Brian:“这会产生指向原始对象的指针”我们在这里讨论的是什么“原始对象”p
不再指向Foo
。它指向一个字节。当你在字节数组指针上执行指针算术时,它停止指向一个Foo
。@Brian:但你引用了CWG1314,说的不是这样。C++17中的任何内容都没有改变这两个方面,因此不清楚您在算术方面关心什么。。CWG最近似乎没有讨论这个问题,但几年前的最新讨论似乎没有明确的方向。@t.C.所以CWG在2011年到2013年之间改变了主意?知道为什么吗?size\t
应该表示对象的大小,可能不足以表示指针。您应该使用uintpr\u t
或intptr\u t
。从整数到指针类型的映射无论如何都是由实现定义的,因此您的代码是否会按预期运行是由实现定义的。无论如何,我看不出答案与这个问题有什么关系。在这个问题上没有积分类型的转换。@walnut这是一种矛盾的证明,但我想你是对的。我更新了答案。