placement new 的 return 值与其操作数的转换值之间是否存在(语义)差异?
Is there a (semantic) difference between the return value of placement new and the casted value of its operand?
placement new 的 return 值与其操作数的转换值之间是否存在(语义)差异?
struct Foo { ... };
char buffer[...];
Foo *a = new(buffer) Foo;
Foo *b = reinterpret_cast<Foo *>(buffer);
a
和 b
有什么不同吗?
编辑:根据 DaBler 的评论,这个问题表明存在差异,如果使用 const/reference 成员:
所以,我的一点点更新问题:如果 Foo
没有 const 或引用成员,a
和 b
有什么不同吗?
通过 a
访问是合法的,而 b
则不是。来自 [basic.compound]
Two objects a
and b
are pointer-interconvertible if:
they are the same object, or
one is a standard-layout union object and the other is a non-static data member of that object, or
one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no non-static data members, the first base class subobject of that object ([class.mem]), or
there exists an object c
such that a
and c
are pointer-interconvertible, and c
and b
are pointer-interconvertible.
If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a reinterpret_cast
. [ Note: An array object and its first element are not pointer-interconvertible, even though they have the same address. — end note ]
它们不是同一个对象,不是联合,也不是彼此的子对象,因此指针不可相互转换。
注意[expr.reinterpret.cast]只保证reinterpret_cast<char*>(b) == buffer
。
An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v
of object pointer type is converted to the object pointer type “pointer to cv T
”, the result is static_cast<cv T*>(static_cast<cv void*>(v))
. [ Note: Converting a prvalue of type “pointer to T1
” to the type “pointer to T2
” (where T1
and T2
are object types and where the alignment requirements of T2
are no stricter than those of T1
) and back to its original type yields the original pointer value. — end note ]
只有 a
可以安全地用于直接访问放置 new-expression 创建的 Foo
对象(我们称之为 x
为了便于参考)。使用 b
需要 std::launder
.
a
的值在[expr.new]/1中指定:
If the entity is a non-array object, the result of the new-expression
is a pointer to the object created.
因此 a
的值为 "pointer to x
"。当然,这个指针可以安全地用于访问 x
.
reinterpret_cast<Foo*>(buffer)
将数组到指针的转换应用于 buffer
(参见 [expr.reinterpret.cast]/1)。应用转换后的结果值为 "pointer to the first element of buffer
"。
这是一个指向不同类型对象指针的对象指针的 reinterpret_cast
,并且被 [expr.reinterpret.cast]/7.
定义为等同于 static_cast<Foo*>(static_cast<void*>(buffer))
到void*
的内部转换实际上是一个隐式转换。每 [conv.ptr]/2,
The pointer value is unchanged by this conversion.
因此,内部转换产生一个 void*
,值为 "pointer to the first element of buffer
"。
外部演员由 [expr.static.cast]/13 管理,我已将其重新格式化为要点:
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.
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.
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。因此,我们击中了第三颗子弹 - "the pointer value is unchanged by the conversion" 并保持 "pointer to the first element of buffer
".
因此,b
不指向Foo
对象x
;它指向 buffer
的第一个 char
元素,即使它的类型是 Foo*
。因此它不能用于访问 x
;尝试这样做会产生未定义的行为(对于非静态数据成员的情况,由于 [expr.ref]; for the non-static member function case, by [class.mfct.non-static]/2 的遗漏)。
要从 b
恢复指向 x
的指针,可以使用 std::launder
:
b = std::launder(b); // value of b is now "pointer to x"
// and can be used to access x
placement new 的 return 值与其操作数的转换值之间是否存在(语义)差异?
struct Foo { ... };
char buffer[...];
Foo *a = new(buffer) Foo;
Foo *b = reinterpret_cast<Foo *>(buffer);
a
和 b
有什么不同吗?
编辑:根据 DaBler 的评论,这个问题表明存在差异,如果使用 const/reference 成员:
所以,我的一点点更新问题:如果 Foo
没有 const 或引用成员,a
和 b
有什么不同吗?
通过 a
访问是合法的,而 b
则不是。来自 [basic.compound]
Two objects
a
andb
are pointer-interconvertible if:
they are the same object, or
one is a standard-layout union object and the other is a non-static data member of that object, or
one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no non-static data members, the first base class subobject of that object ([class.mem]), or
there exists an object
c
such thata
andc
are pointer-interconvertible, andc
andb
are pointer-interconvertible.If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a
reinterpret_cast
. [ Note: An array object and its first element are not pointer-interconvertible, even though they have the same address. — end note ]
它们不是同一个对象,不是联合,也不是彼此的子对象,因此指针不可相互转换。
注意[expr.reinterpret.cast]只保证reinterpret_cast<char*>(b) == buffer
。
An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue
v
of object pointer type is converted to the object pointer type “pointer tocv T
”, the result isstatic_cast<cv T*>(static_cast<cv void*>(v))
. [ Note: Converting a prvalue of type “pointer toT1
” to the type “pointer toT2
” (whereT1
andT2
are object types and where the alignment requirements ofT2
are no stricter than those ofT1
) and back to its original type yields the original pointer value. — end note ]
只有 a
可以安全地用于直接访问放置 new-expression 创建的 Foo
对象(我们称之为 x
为了便于参考)。使用 b
需要 std::launder
.
a
的值在[expr.new]/1中指定:
If the entity is a non-array object, the result of the new-expression is a pointer to the object created.
因此 a
的值为 "pointer to x
"。当然,这个指针可以安全地用于访问 x
.
reinterpret_cast<Foo*>(buffer)
将数组到指针的转换应用于 buffer
(参见 [expr.reinterpret.cast]/1)。应用转换后的结果值为 "pointer to the first element of buffer
"。
这是一个指向不同类型对象指针的对象指针的 reinterpret_cast
,并且被 [expr.reinterpret.cast]/7.
static_cast<Foo*>(static_cast<void*>(buffer))
到void*
的内部转换实际上是一个隐式转换。每 [conv.ptr]/2,
The pointer value is unchanged by this conversion.
因此,内部转换产生一个 void*
,值为 "pointer to the first element of buffer
"。
外部演员由 [expr.static.cast]/13 管理,我已将其重新格式化为要点:
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.
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.Otherwise, if the original pointer value points to an object
a
, and there is an objectb
of typeT
(ignoring cv-qualification) that is pointer-interconvertible witha
, the result is a pointer tob
.Otherwise, the pointer value is unchanged by the conversion.
假设 buffer
已适当对齐(如果不是,您在此之前就会遇到麻烦),第一个项目符号不适用。第二个项目符号同样不适用,因为这里没有 pointer-interconvertiblity。因此,我们击中了第三颗子弹 - "the pointer value is unchanged by the conversion" 并保持 "pointer to the first element of buffer
".
因此,b
不指向Foo
对象x
;它指向 buffer
的第一个 char
元素,即使它的类型是 Foo*
。因此它不能用于访问 x
;尝试这样做会产生未定义的行为(对于非静态数据成员的情况,由于 [expr.ref]; for the non-static member function case, by [class.mfct.non-static]/2 的遗漏)。
要从 b
恢复指向 x
的指针,可以使用 std::launder
:
b = std::launder(b); // value of b is now "pointer to x"
// and can be used to access x