在标准布局对象(例如,使用offsetof)内进行指针算术时,我们需要使用std :: launder吗? [英] Do we need to use std::launder when doing pointer arithmetic within a standard-layout object (e.g., with offsetof)?
问题描述
This question is a follow-up to: Is adding to a "char *" pointer UB, when it doesn't actually point to a char array?
在 CWG 1314 中,CWG确认使用unsigned char
指针在标准布局对象中执行指针算术是合法的.这似乎意味着某些与链接的问题中的代码相似的代码应按预期的方式工作:
In CWG 1314, CWG affirmed that it is legal to perform pointer arithmetic within a standard-layout object using an unsigned char
pointer. This would appear to imply that some code similar to that in the linked question should work as intended:
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;
(为清楚起见,我已将char
替换为unsigned char
.)
(I have replaced char
with unsigned char
for greater clarity.)
但是,似乎C ++ 17中的新变化意味着该代码现在是UB,除非在两个reinterpret_cast
之后都使用std::launder
.两种指针类型之间的reinterpret_cast
结果等于两个static_cast
:第一个为 cv void*
,第二个为目标指针类型.但是[expr.static.cast]/13暗示这会生成指向原始对象的指针,而不是指向目标类型的对象的指针,因为类型Foo
的对象不能与unsigned char
对象的指针互换.它的第一个字节,f.z
指针的第一个字节处的unsigned char
对象也不能与f.z
本身互换.
However, it seems that the new changes in C++17 imply that this code is now UB unless std::launder
is used after both reinterpret_cast
s. The result of a reinterpret_cast
between two pointer types is equivalent to two static_cast
s: the first to cv void*
, the second to the destination pointer type. But [expr.static.cast]/13 implies that this produces a pointer to the original object, not to an object of the destination type, since an object of type Foo
is not pointer-interconvertible with an unsigned char
object at its first byte, nor is an unsigned char
object at the first byte of f.z
pointer-interconvertible with f.z
itself.
我很难相信委员会打算进行更改以打破这种非常普遍的习惯用法,从而使offsetof
的所有C ++ 17以前的用法都不确定.
I find it hard to believe that the committee intended a change that would break this very common idiom, making all pre-C++17 usages of offsetof
undefined.
推荐答案
您的问题是:
在一个指针内进行指针算术时,我们需要使用std :: launder吗? 标准布局对象(例如,具有offsetof的对象)?
Do we need to use std::launder when doing pointer arithmetic within a standard-layout object (e.g., with offsetof)?
否.
std::launder
在这种情况下不会更改任何内容,因此与所提供的示例无关( imo 在问题之外编辑洗钱或提出其他问题).
std::launder
won't change anything in this case and therefore has nothing to do with the presented example (imo edit launder out of the question or ask another question).
std::launder
通常仅在某些情况下才需要使用(例如,由于const成员所致),在这种情况下,您需要在某些运行时基础对象 >方式(例如,通过新的展示位置).助记符:该对象是脏"的,需要std::launder
编辑.
std::launder
is usually just needed in a subset of cases (eg. due to a const member) where you change (or create) an underlying object in some runtime manner (eg. via placement new). Mnemonic: the object is 'dirty' and needs to be std::launder
'ed.
仅使用标准布局类型不会导致您需要使用std :: launder的情况.
这篇关于在标准布局对象(例如,使用offsetof)内进行指针算术时,我们需要使用std :: launder吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!