una resueltos resolucion que programacion orientada operador objetos miembros ejercicios ejemplos codigo clases clase ambito c++ c++11 language-lawyer c++17

resueltos - programacion orientada a objetos ejemplos c++



reinterpret_cast creando un objeto trivialmente construible por defecto (2)

Este análisis se basa en n4567 y utiliza números de sección de él.

§5.2.10 / 7: cuando un valor pr v del tipo de puntero de objeto se convierte en el tipo de puntero de objeto "puntero a cv T", el resultado es static_cast<cv T*>(static_cast<cv void*>(v)) .

Entonces, en este caso, reinterpret_cast<X*>(buffer) es el mismo que static_cast<X *>(static_cast<void *>(buffer)) . Eso nos lleva a mirar las partes relevantes sobre static_cast :

§5.2.9 / 13: Un valor de tipo "puntero a cv1 vacío" se puede convertir en un valor de tipo "puntero a cv2 T", donde T es un tipo de objeto y cv2 es la misma calificación de cv o mayor cv-calificación que, cv1 . El valor del puntero nulo se convierte en el valor del puntero nulo del tipo de destino. Si el valor del puntero original representa la dirección A de un byte en la memoria y A satisface el requisito de alineación de T , entonces el valor del puntero resultante representa la misma dirección que el valor del puntero original, es decir, A

Creo que eso es suficiente para decir que la cita original es más o menos correcta: esta conversión da resultados definidos.

En cuanto a la vida, depende de la vida de la que estés hablando. El reparto crea un nuevo objeto de tipo puntero, temporal, que tiene una vida útil que comienza desde la línea donde se encuentra el reparto y termina cada vez que sale del alcance. Si tiene dos conversiones diferentes que ocurren condicionalmente, cada puntero tiene una vida útil que comienza desde la ubicación del molde que lo creó.

Ninguno de estos afecta la vida útil del objeto que proporciona el almacenamiento subyacente, que todavía es buffer , y tiene exactamente la misma vida útil, independientemente de si crea un puntero (del mismo tipo o convertido) a ese almacenamiento o no.

cppreference establece que:

Los objetos con constructores predeterminados triviales se pueden crear utilizando reinterpret_cast en cualquier almacenamiento adecuadamente alineado, por ejemplo, en la memoria asignada con std::malloc .

Esto implica que el siguiente es un código bien definido:

struct X { int x; }; alignas(X) char buffer[sizeof(X)]; // (A) reinterpret_cast<X*>(buffer)->x = 42; // (B)

Siguen tres preguntas:

  1. ¿Es correcta esa cita?
  2. En caso afirmativo, ¿en qué punto comienza la vida útil de la X ? Si está en la línea (B) , ¿es el yeso en sí mismo el que se considera adquirir almacenamiento? Si está en la línea (A) , ¿qué pasaría si hubiera una rama entre (A) y (B) que construiría condicionalmente una X o alguna otra vaina, Y ?
  3. ¿Algo cambia entre C ++ 11 y C ++ 1z a este respecto?

Tenga en cuenta que este es un enlace antiguo. La redacción se cambió en respuesta a esta pregunta. Ahora se lee:

Sin embargo, a diferencia de C, los objetos con constructores triviales predeterminados no se pueden crear simplemente reinterpretando el almacenamiento adecuadamente alineado, como la memoria asignada con std::malloc : position-new es necesaria para introducir formalmente un nuevo objeto y evitar un posible comportamiento indefinido.


No hay ningún objeto X , vivo o de otro tipo, por lo que simular que hay uno da como resultado un comportamiento indefinido.

[intro.object]/1 explica exhaustivamente cuando se crean objetos:

Un objeto es creado por una definición ([basic.def]), por una nueva expresión ([expr.new]), cuando se cambia implícitamente el miembro activo de una unión ([class.union]), o cuando un objeto temporal es creado ([conv.rval], [class.temporary]).

Con la adopción de P0137R1 , este párrafo es la definición del término "objeto".

¿Existe una definición de un objeto X ? No. ¿Hay una nueva expresión ? No. ¿Hay un sindicato? No. ¿Hay una construcción de lenguaje en su código que crea un objeto X temporal? No.

Lo que dice [basic.life] sobre la vida útil de un objeto con inicialización vacía es irrelevante. Para que eso se aplique, debes tener un objeto en primer lugar. Usted no

C ++ 11 tiene aproximadamente el mismo párrafo, pero no lo usa como la definición de "objeto". No obstante, la interpretación es la misma. La interpretación alternativa, tratar [basic.life] como la creación de un objeto tan pronto como se obtiene el almacenamiento adecuado, significa que está creando los objetos de Schrödinger * , lo que contradice a N3337 [intro.object] / 6 :

Dos objetos que no son campos de bits pueden tener la misma dirección si uno es un subobjeto del otro, o si al menos uno es un subobjeto de clase base de tamaño cero y son de diferentes tipos; de lo contrario, tendrán direcciones distintas.

* El almacenamiento con la alineación y el tamaño adecuados para un tipo T es, por definición, un almacenamiento con la alineación y el tamaño adecuados para cualquier otro tipo cuyos requisitos de tamaño y alineación sean iguales o menores que los de T Por lo tanto, esa interpretación significa que obtener el almacenamiento simultáneamente crea un conjunto infinito de objetos con diferentes tipos en dicho almacenamiento, todos con la misma dirección.