gez*_*eza 13 c++ strict-aliasing placement-new language-lawyer reinterpret-cast
放置new的返回值与其操作数的转换值之间是否存在(语义)差异?
struct Foo { ... };
char buffer[...];
Foo *a = new(buffer) Foo;
Foo *b = reinterpret_cast<Foo *>(buffer);
Run Code Online (Sandbox Code Playgroud)
是否a
和b
以某种方式有什么不同?
编辑:根据DaBler的评论,这个问题告诉我,如果使用const/reference成员则存在差异:使用const成员放置新类和赋值
所以,我的小位的更新问题:是否a
和b
以任何方式不同,如果Foo
没有const或引用成员?
T.C*_*.C. 15
只能a
安全地用于直接访问Foo
由放置new-expression创建的对象(我们将调用它x
以便于参考).使用b
要求std::launder
.
值a
在[expr.new]/1中指定:
如果实体是非数组对象,则new-expression的结果 是指向创建的对象的指针.
因此,值a
是"指向x
".当然,这个指针可以安全地用于访问x
.
reinterpret_cast<Foo*>(buffer)
应用数组到指针的转换buffer
(参见[expr.reinterpret.cast]/1).应用转换后的结果值是"指向第一个元素的指针buffer
".这是一个reinterpret_cast
对象的指针到一个不同类型的对象的指针,并且被定义为等同于static_cast<Foo*>(static_cast<void*>(buffer))
由[expr.reinterpret.cast]/7.
内部void*
强制转换实际上是一种隐式转换.每[conv.ptr]/2,
此转换不会改变指针值.
因此,内部强制转换产生一个void*
值为"指向第一个元素的指针buffer
".
外部演员由[expr.static.cast]/13管理,我已经轻轻地重新格式化为要点:
"到指针类型的prvalue CV1
void
"可以被转换成类型的prvalue"指针CV2T
",其中T
是一个对象类型和CV2是相同的CV-资格,或更大的CV-资格比,CV1.
如果原始指针值表示
A
内存中字节的地址并且A
不满足对齐要求T
,则未指定结果指针值.否则,如果原始指针值指向一个对象
a
,并且存在一个b
类型T
(忽略cv-qualification)的对象,该对象是指针可互换的a
,则结果是指向的对象b
.否则,转换指针值不变.
假设它buffer
是适当对齐的(如果不是,那么在此之前你会遇到麻烦),第一个子弹是不适用的.第二个子弹同样不适用,因为这里没有指针 - 互换性.接下来我们点击第三个子弹 - "转换时指针值不变"并保持"指向第一个元素的指针buffer
".
因此,b
不指向Foo
对象x
; 它指向第一个char
元素buffer
,即使它的类型是Foo*
.因此它不能用于访问x
; 尝试这样做会产生未定义的行为(对于非静态数据成员的情况,通过省略[expr.ref] ;对于非静态成员函数的情况,通过[class.mfct.non-static]/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
Run Code Online (Sandbox Code Playgroud)
通过访问a
是合法的,而通过b
是不合法的。来自[基本化合物]
\n\n两个对象
\na
和b
是指针可相互转换的,如果:\n
\n- \n
它们是同一个对象,或者
\n- \n
一个是标准布局联合对象,另一个是该对象的非静态数据成员,或者
\n- \n
一个是标准布局类对象,另一个是该对象的第一个非静态数据成员,或者,如果该对象没有非静态数据成员,则该对象的第一个基类子对象 ([class.mem] ), 或者
\n- \n
存在一个对象
\nc
,使得a
和c
是指针可相互转换的,并且c
和b
是指针可相互转换的。如果两个对象是指针可相互转换的,那么它们具有相同的地址,并且可以通过
\nreinterpret_\xc2\xadcast
. [\xe2\x80\x89注意:数组对象及其第一个元素不可进行指针互换,即使它们具有相同的地址。\xe2\x80\x89\xe2\x80\x94\xe2\x80\x89尾注\xe2\x80\x89]
它们不是同一个对象,不是联合体,也不是彼此的子对象,因此不能进行指针相互转换。
\n注意[expr.reinterpret.cast]仅保证reinterpret_cast<char*>(b) == buffer
.
\n\n对象指针可以显式转换为不同类型的对象指针。当对象指针类型的纯右值
\nv
转换为对象指针类型 \xe2\x80\x9cpointer tocv T
\xe2\x80\x9d 时,结果为static_\xc2\xadcast<cv T*>(static_\xc2\xadcast<cv void*>(v))
。[\xe2\x80\x89注意:将 \xe2\x80\x9cpointer 类型的纯右值转换为T1
\xe2\x80\x9d 到 \xe2\x80\x9cpointer 类型的纯右值到T2
\xe2\x80\x9d (其中T1
和T2
是对象类型,其中的对齐要求T2
并不比T1
) 更严格,并且返回到其原始类型会产生原始指针值。\xe2\x80\x89\xe2\x80\x94\xe2\x80\x89尾注\xe2\x80\x89]
归档时间: |
|
查看次数: |
488 次 |
最近记录: |