c++ - semantica - ¿Existe una diferencia(semántica) entre el valor de retorno de la ubicación nueva y el valor emitido de su operando?
sintaxis y semantica ejemplos (2)
El acceso a través de
a
es legal mientras que
b
no lo es.
De
[basic.compound]
Dos objetos
b
son interconvertibles por puntero si:
son el mismo objeto, o
uno es un objeto de unión de diseño estándar y el otro es un miembro de datos no estático de ese objeto, o
uno es un objeto de clase de diseño estándar y el otro es el primer miembro de datos no estáticos de ese objeto o, si el objeto no tiene miembros de datos no estáticos, el primer subobjeto de clase base de ese objeto ([class.mem] ) o
existe un objeto
c
tal quec
son interconvertibles por puntero,c
yb
son interconvertibles por puntero.Si dos objetos son interconvertibles por puntero, tienen la misma dirección y es posible obtener un puntero a uno de un puntero a otro a través de un
reinterpret_cast
. [Nota: un objeto de matriz y su primer elemento no son interconvertibles por puntero, aunque tengan la misma dirección. - nota final]
No son el mismo objeto, ni uniones ni subobjetos entre sí, por lo tanto, no son interconvertibles por puntero.
Nota
[expr.reinterpret.cast]
solo garantiza
reinterpret_cast<char*>(b) == buffer
.
Un puntero de objeto puede convertirse explícitamente en un puntero de objeto de un tipo diferente. Cuando un valor pr
v
del tipo de puntero de objeto se convierte en el tipo de puntero de objeto "puntero acv T
", el resultado esstatic_cast<cv T*>(static_cast<cv void*>(v))
. [Nota: Convertir un prvalor de tipo "puntero aT1
" en el tipo "puntero aT2
" (dondeT1
yT2
son tipos de objeto y donde los requisitos de alineación deT2
no son más estrictos que los deT1
) y volver a su tipo original produce el valor del puntero original. - nota final]
¿Existe una diferencia (semántica) entre el valor de retorno de la ubicación nueva y el valor emitido de su operando?
struct Foo { ... };
char buffer[...];
Foo *a = new(buffer) Foo;
Foo *b = reinterpret_cast<Foo *>(buffer);
¿A y
b
difieren de alguna manera?
EDITAR: Basado en el comentario de DaBler, esta pregunta dice que hay una diferencia, si se usan miembros const / reference: colocación nueva y asignación de clase con miembro const
Entonces, mi pregunta
a
poco actualizada: ¿A y
b
difieren de alguna manera, si
Foo
no tiene miembros constantes o de referencia?
Solo se puede usar de forma segura para acceder directamente al objeto
Foo
creado por la
nueva expresión de
ubicación (que llamaremos
x
para facilitar la referencia).
El uso de
b
requiere
std::launder
.
El valor de
a
se especifica en
[expr.new]/1
:
Si la entidad es un objeto sin matriz, el resultado de la nueva expresión es un puntero al objeto creado.
El valor de
a
es, por lo tanto, "puntero a
x
".
Este puntero, por supuesto, se puede usar de forma segura para acceder a
x
.
reinterpret_cast<Foo*>(buffer)
aplica la conversión de matriz a puntero a
buffer
(ver
[expr.reinterpret.cast]/1
).
El valor resultante después de aplicar la conversión es "puntero al primer elemento del
buffer
".
Este es un
reinterpret_cast
de un puntero de objeto a un puntero de objeto de un tipo diferente, y se define como equivalente a
static_cast<Foo*>(static_cast<void*>(buffer))
por
[expr.reinterpret.cast]/7
.
El lanzamiento interno a
void*
es en realidad una conversión implícita.
Por
[conv.ptr]/2
,
El valor del puntero no cambia con esta conversión.
Por lo tanto, el molde interno produce un
void*
con el valor "puntero al primer elemento del
buffer
".
El molde externo se rige por [expr.static.cast]/13 , que he formateado ligeramente en viñetas:
Un valor prva de tipo "puntero a
void
cv1 " se puede convertir en un valor prolo de tipo "puntero a cv2T
", dondeT
es un tipo de objeto y cv2 es la misma calificación cv o mayor calificación cv que cv1 .
Si el valor del puntero original representa la dirección
A
de un byte en la memoria yA
no satisface el requisito de alineación deT
, entonces el valor del puntero resultante no está especificado.De lo contrario, si el valor del puntero original apunta a un objeto
a
, y hay un objetob
de tipoT
(ignorando la calificación cv) que es interconvertible por puntero cona
, el resultado es un puntero ab
.De lo contrario, la conversión no modifica el valor del puntero.
Suponiendo que el
buffer
esté alineado adecuadamente (si no lo fuera, estaría en problemas mucho antes de este punto), la primera viñeta no es aplicable.
La segunda viñeta también es inaplicable ya que no hay
pointer-interconvertiblity
aquí.
De esto se deduce que tocamos la tercera viñeta: "el valor del puntero no ha cambiado por la conversión" y sigue siendo "puntero al primer elemento del
buffer
".
Por lo tanto,
b
no apunta al objeto
Foo
x
;
señala, en cambio, el primer elemento
char
del
buffer
, aunque su tipo es
Foo*
.
Por lo tanto, no se puede usar para acceder a
x
;
intentar hacerlo produce un comportamiento indefinido (para el caso de miembro de datos no estático, por omisión de
[expr.ref]
; para el caso de función de miembro no estático, por
[class.mfct.non-static]/2
).
Para recuperar un puntero a
x
desde
b
, se puede usar
std::launder
:
b = std::launder(b); // value of b is now "pointer to x"
// and can be used to access x