位置new的返回值与其操作数的强制转换值之间是否有(语义上的)区别? [英] Is there a (semantic) difference between the return value of placement new and the casted value of its operand?
问题描述
new位置的返回值与其操作数的强制转换值之间是否存在(语义)差异?
Is there a (semantic) difference between the return value of placement new and the casted value of its operand?
struct Foo { ... };
char buffer[...];
Foo *a = new(buffer) Foo;
Foo *b = reinterpret_cast<Foo *>(buffer);
a
和b
有所不同吗?
基于DaBler的评论,此问题告诉我们,如果使用const/reference成员,则存在区别:
Based on DaBler's comment, this question tells that there is a difference, if const/reference members used: Placement new and assignment of class with const member
所以,我的最新问题是:a
和b
是否没有任何区别,如果Foo
没有const或引用成员?
So, my little-bit updated question: Does a
and b
differ in any way, if Foo
doesn't have const or reference members?
推荐答案
只有a
可以安全地用于直接访问由展示位置 new-expression 创建的Foo
对象为了方便参考,请致电x
).使用b
需要std::launder
.
Only a
can safely be used to directly access the Foo
object created by the placement new-expression (which we'll call x
for ease of reference). Using b
requires std::launder
.
a
的值在 [expr.新]/1 :
如果实体是非数组对象,则 new-expression 的结果 是指向创建的对象的指针.
If the entity is a non-array object, the result of the new-expression is a pointer to the object created.
因此a
的值是指向x
的指针".当然,该指针可以安全地用于访问x
.
The value of a
is therefore "pointer to x
". This pointer, of course, can safely be used to access x
.
reinterpret_cast<Foo*>(buffer)
将数组到指针的转换应用于buffer
(请参阅reinterpret_cast,并且由
reinterpret_cast<Foo*>(buffer)
applies the array-to-pointer conversion to buffer
(see [expr.reinterpret.cast]/1). The resulting value after the conversion is applied is "pointer to the first element of buffer
".
This is a reinterpret_cast
of an object pointer to an object pointer of a different type, and is defined as equivalent to static_cast<Foo*>(static_cast<void*>(buffer))
by [expr.reinterpret.cast]/7.
对void*
的内部强制转换实际上是一个隐式转换.每个 [conv.ptr]/2 ,
The inner cast to void*
is actually an implicit conversion. Per [conv.ptr]/2,
此转换未更改指针值.
The pointer value is unchanged by this conversion.
因此,内部强制转换产生的void*
值为指向buffer
的第一个元素的指针".
Therefore the inner cast yields a void*
with the value "pointer to the first element of buffer
".
外部演员表受 [expr.static.cast]/13 ,我已将其重新格式化为要点:
The outer cast is governed by [expr.static.cast]/13, which I've lightly reformatted into bullet points:
可以将指向 cv1
void
的指针"类型的prvalue转换为指向 cv2T
的指针"的prvalue,其中T
是对象类型,并且 cv2 与 cv1 具有相同的cv限定,或具有更高的cv限定.
A prvalue of type "pointer to cv1
void
" can be converted to a prvalue of type "pointer to cv2T
", whereT
is an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1.
-
如果原始指针值表示内存中字节的地址
A
,并且A
不满足T
的对齐要求, 那么未指定结果指针值.
If the original pointer value represents the address
A
of a byte in memory andA
does not satisfy the alignment requirement ofT
, then the resulting pointer value is unspecified.
否则,如果原始指针值指向对象a
,并且存在类型为T
的对象b
(忽略cv限定)
可以与a
进行指针互转换,结果是指向的指针
b
.
Otherwise, if the original pointer value points to an object a
, and there is an object b
of type T
(ignoring cv-qualification)
that is pointer-interconvertible with a
, the result is a pointer to
b
.
否则,转换后指针值将保持不变.
Otherwise, the pointer value is unchanged by the conversion.
假设buffer
已正确对齐(如果没有,您可能会在此之前遇到麻烦),第一个项目符号不适用.第二个项目符号同样不适用,因为这里没有 pointer-interconvertiblity .因此,我们遇到了第三个项目符号-转换后指针值未更改",并保持指向buffer
的第一个元素的指针".
Assuming that buffer
is suitably aligned (you'd be in trouble well before this point if it's not), the first bullet is inapplicable. The second bullet is likewise inapplicable as there's no pointer-interconvertiblity here. It follows that we hit the third bullet - "the pointer value is unchanged by the conversion" and remains "pointer to the first element of buffer
".
因此,b
并不指向Foo
对象x
;即使它的类型是Foo*
,它也指向buffer
的第一个char
元素.因此,它不能用于访问x
.尝试这样做会产生不确定的行为(对于非静态数据成员的情况,通过省略 [expr.ref] ;对于非静态成员函数案例,通过 [class.mfct.non-static]/2 ).
Thus, b
does not point to the Foo
object x
; it points instead to the first char
element of buffer
, even though its type is Foo*
. It therefore cannot be used to access x
; attempting to do so yields undefined behavior (for the non-static data member case, by omission from [expr.ref]; for the non-static member function case, by [class.mfct.non-static]/2).
要从b
恢复指向x
的指针,可以使用std::launder
:
To recover a pointer to x
from b
, std::launder
can be used:
b = std::launder(b); // value of b is now "pointer to x"
// and can be used to access x
这篇关于位置new的返回值与其操作数的强制转换值之间是否有(语义上的)区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!