位置new的返回值与其操作数的强制转换值之间是否有(语义上的)区别? [英] Is there a (semantic) difference between the return value of placement new and the casted value of its operand?

查看:108
本文介绍了位置new的返回值与其操作数的强制转换值之间是否有(语义上的)区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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);

ab有所不同吗?

基于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

所以,我的最新问题是:ab是否没有任何区别,如果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,并且由static_cast<Foo*>(static_cast<void*>(buffer))等效. reinterpret.cast#7.sentence-2"rel =" noreferrer> [expr.reinterpret.cast]/7 .

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转换为指向 cv2 T的指针"的prvalue,其中T是对象类型,并且 cv2 cv1 具有相同的cv限定,或具有更高的cv限定.

A prvalue of type "pointer to cv1 void" can be converted to a prvalue of type "pointer to cv2 T", where T 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 and A does not satisfy the alignment requirement of T, 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆