una resueltos que programacion orientada objetos miembros ejercicios ejemplos codigo clases clase c++ placement-new

resueltos - programacion orientada a objetos c++ ejemplos



Destruye y luego construye un nuevo objeto usando la misma variable (6)

Creo que la única forma de que esto sea realmente seguro de usar es exigir que el constructor llamado sea noexcept , por ejemplo agregando un static_assert :

static_assert(noexcept(T(22, Brown, true)), "The constructor must be noexcept for inplace reconstruction"); T x(31, Blue, false); x.~T(); ::new (&x) T(22, Brown, true);

Por supuesto, esto solo funcionará para C ++ 11.

A veces es bueno comenzar de nuevo. En C ++ puedo emplear esta siguiente maniobra simple:

{ T x(31, Blue, false); x.~T(); // enough with the old x ::new (&x) T(22, Brown, true); // in with the new! // ... }

Al final del alcance, el destructor se ejecutará una vez más y todo parece estar bien. (Digamos también que T es un poco especial y no le gusta que lo asignen, y mucho menos que lo intercambien). Pero algo me dice que no siempre es sin riesgo destruir todo e intentarlo de nuevo. ¿Hay una posible captura con este enfoque?


Mmm. Ya que estás haciendo todo lo que C ++ desalienta, creo que todos se están olvidando de Goto .

Tenga en cuenta que después de la llamada explícita X.~T() , y antes de que se reconstruya 1 , aún habría destrucción doble si alguien hiciera un goto antes de la declaración / inicialización de la variable x ( incluso dentro del bloque de alcance interno ).

Como obviamente podrías documentar eso, no pasaré por la molestia de tratar de ''arreglar'' esto. Podría, conceptualmente, diseñar una clase RAII para gestionar la reconstrucción de objetos en el lugar, haciendo que esta maniobra sea segura para los goto en cualquier lugar. Tenga en cuenta que puede hacer que la llamada de constructor de ubicación-nueva se reenvíe perfectamente desde el destructor del objeto administrador RAII. La vida es buena.

Las otras advertencias aún se aplican, por supuesto (ver otras respuestas)

1 podemos suponer que no hay construcción para este momento


No hay nada que te impida hacer esto, funcionará en la mayoría de los casos. Pero como es el caso en una gran cantidad de C ++ sabiendo que los detalles de sus casos será la diferencia entre que funcione como desee y un volcado de núcleo. Hay muy pocos ejemplos de razones por las que podría ver por qué querría hacer esto en un programa real, el único que tiene sentido es un archivo mapeado en la memoria.


Si el constructor de T lanza en la segunda construcción, tienes un problema. Si te gustan los enfoques de fuerza bruta, mira esto:

T x(31, Blue, false); x.~T(); const volatile bool _ = true; for(;_;){ try{ ::new (&x) T(22, Brown, true); break; // finally! }catch(...){ continue; // until it works, dammit! } }

¡Incluso proporciona la fuerte garantía de excepción!

En una nota más seria, es como pisar una mina terrestre, sabiendo que se activará si mueves el pie ...

Y realmente hay una forma de evitar el comportamiento indefinido de la doble destrucción aquí:

#include <cstdlib> T x(31, Blue, false); x.~T(); try{ ::new (&x) T(22, Brown, true); }catch(...){ std::exit(1); // doesn''t call destructors of automatic objects }


Si la expresión de construcción de T arroja, se duplicará la destrucción del objeto, que es UB. Por supuesto, incluso el deseo de hacer esto es indicativo de una falla de diseño.


Traté de compilarlo, pero solo me atreví a ejecutarlo bajo depurador. Así que eché un vistazo al desmontaje que generó mi compilador anterior (los comentarios son también del compilador):

@1 sub nerve.cells, fa0h @2 xor x, x // bitch. @3 mov out, x @4 test out, out @5 jne @1 @6 xor x, x // just in case. @7 sub money, 2BC // dammit. @8 mov %x, new.one @8 cmp new.one, %x @9 jne @7 ... @25 jmp @1 // sigh...