Only a
可以安全地用于直接访问Foo
由放置创建的对象新表达(我们称之为x
以便于参考)。使用b
需要std::launder
.
的价值a
指定于[expr.new]/1:
如果实体是非数组对象,则结果新表达是指向所创建对象的指针。
的价值a
因此是“指向x
”。当然,这个指针可以安全地用于访问x
.
reinterpret_cast<Foo*>(buffer)
将数组到指针的转换应用于buffer
(see [expr.reinterpret.cast]/1)。应用转换后的结果值是“指向第一个元素的指针”buffer
”。
这是一个reinterpret_cast
对象指针指向不同类型的对象指针,并且被定义为等价于static_cast<Foo*>(static_cast<void*>(buffer))
by [expr.reinterpret.cast]/7.
内部演员阵容void*
实际上是隐式转换。每[转化指针]/2,
此转换不会改变指针值。
因此,内部铸件产生void*
值为“指向第一个元素的指针buffer
".
外部演员受制于[expr.static.cast]/13,我将其稍微重新格式化为要点:
“指向的指针”类型的纯右值cv1 void
” 可以转换为“指向的指针”类型的纯右值cv2 T
“, 在哪里T
是一个对象类型并且cv2简历资格与以下相同或更高:cv1.
如果原始指针值代表地址A
内存中的一个字节和A
不满足对齐要求T
,
那么结果指针值是未指定的。
否则,如果原始指针值指向一个对象a
,并且有一个对象b
类型的T
(忽略简历资格)
这是指针可相互转换的a
,结果是一个指向b
.
否则,指针值不会因转换而改变。
假如说buffer
已适当对齐(如果不是,那么在此之前您就会遇到麻烦),第一个项目符号不适用。第二条同样不适用,因为没有指针互换性这里。接下来,我们击中了第三个项目符号 - “指针值不会因转换而改变”,并且仍然是“指向第一个元素的指针”buffer
".
Thus, b
没有指向Foo
object x
;它指向第一个char
的元素buffer
,尽管它的类型是Foo*
。因此它不能用于访问x
;尝试这样做会产生未定义的行为(对于非静态数据成员的情况,通过省略[expr.ref];对于非静态成员函数的情况,通过[class.mfct.非静态]/2).
恢复指向x
from b
, std::launder
可以使用:
b = std::launder(b); // value of b is now "pointer to x"
// and can be used to access x