new - pointer c++
Llama al destructor y luego al constructor(restableciendo un objeto) (10)
¿Por qué no implementar un método Clear () que hace lo que hace el código en el cuerpo del destructor? El destructor simplemente llama a Clear () y usted a Clear () directamente sobre un objeto para "restablecerlo".
Otra opción, asumiendo que tu clase admite la asignación correctamente:
MyClass a;
...
a = MyClass();
Uso este patrón para restablecer instancias std :: stack, ya que el adaptador de pila no proporciona una función clara.
Quiero restablecer un objeto. ¿Puedo hacerlo de la siguiente manera?
anObject->~AnObject();
anObject = new(anObject) AnObject();
// edit: this is not allowed: anObject->AnObject();
Este código es obviamente un subconjunto del ciclo de vida típico de un objeto asignado en una nueva ubicación:
AnObject* anObject = malloc(sizeof(AnObject));
anObject = new (anObject) AnObject(); // My step 2.
// ...
anObject->~AnObject(); // My step 1.
free(anObject)
// EDIT: The fact I used malloc instead of new doesn''t carry any meaning
Lo único que ha cambiado es el orden de las llamadas de constructor y destructor.
Entonces, ¿por qué en las siguientes preguntas frecuentes aparecen todas las amenazas?
[11.9] Pero, ¿puedo llamar explícitamente a un destructor si le he asignado un objeto nuevo a mi objeto?
Preguntas frecuentes: No puede hacerlo, a menos que el objeto haya sido asignado con una ubicación nueva. Los objetos creados por nuevo deben eliminarse, lo que hace dos cosas (recuérdelos): llama al destructor y luego libera la memoria.
FQA: Traducción: eliminar es una forma de llamar explícitamente a un destructor, pero también desasigna la memoria. También puede llamar a un destructor sin desasignar la memoria. Es feo e inútil en la mayoría de los casos, pero puedes hacerlo.
La llamada destructor / constructor es obviamente un código C ++ normal. Las garantías utilizadas en el código resultan directamente de las nuevas garantías de colocación. Es el núcleo de la norma , es cosa de roca sólida. ¿Cómo puede llamarse "sucio" y presentarse como algo no confiable?
¿Crees que es posible que la implementación de nuevos y no colocados sea diferente? Estoy pensando en alguna posibilidad enfermiza, que la nueva regular, por ejemplo, puede poner el tamaño del bloque de memoria asignado antes que el bloque, lo que obviamente no sería suficiente con la nueva ubicación (porque no asigna ninguna memoria). Esto podría generar una brecha para algunos problemas ... ¿Es posible tal implementación nueva ()?
¿Por qué no reiniciar utilizando el operador = ()? Esto no es discutible y mucho más legible.
A a;
//do something that changes the state of a
a = A(); // reset the thing
Es mucho mejor simplemente agregar algo como un método Reset () a su objeto en lugar de jugar con ubicaciones nuevas.
Está explotando la nueva función de ubicación que está diseñada para permitirle controlar dónde se asigna un objeto. Por lo general, esto solo es un problema si su hardware tiene una memoria "especial" como un chip flash. Si desea colocar algunos objetos en el chip flash, puede utilizar esta técnica. La razón por la que le permite llamar explícitamente al destructor es que USTED está ahora en control de la memoria, por lo que el compilador de C ++ no sabe cómo hacer la parte de desasignación de la eliminación.
Tampoco le está ahorrando mucho código, con un método de restablecimiento, tendrá que configurar los miembros a sus valores iniciales. malloc () no hace eso, así que tendrás que escribir ese código en el constructor de todos modos. Simplemente haga una función que establezca a sus miembros en los valores iniciales, llámela Restablecer () llámela desde el constructor y también desde cualquier otro lugar que necesite.
No puede llamar al constructor de esa manera, pero no hay nada de malo en reutilizar la memoria y llamar a la ubicación nueva, siempre y cuando no borre o libere (desasigne) la memoria. Debo decir que reiniciar un objeto como este es un poco incompleto. Escribiría un objeto para que se pueda reajustar explícitamente, o escribiría un método de intercambio y lo usaría para restablecerlo.
P.ej
anObject.swap( AnObject() ); // swap with "clean" object
No puede llamar al constructor de la manera indicada por usted. En su lugar, puede hacerlo utilizando la ubicación nueva (como indica también su código):
new (anObject) AnObject();
Se garantiza que este código estará bien definido si la ubicación de la memoria aún está disponible, como debería ser en su caso.
(He eliminado la parte sobre si este es un código discutible o no, está bien definido. Parada completa).
Por cierto, Brock tiene razón: cómo la implementación de la delete
no está arreglada, no es lo mismo que llamar al destructor, seguido de free
. Siempre empareje llamadas de new
y delete
, nunca mezcle una con la otra: eso no está definido.
No te dejes atrapar por el troll FQA. Como de costumbre se equivoca en los hechos.
Ciertamente, puede llamar al destructor directamente, para todos los objetos, ya sea que se creen con una ubicación nueva o no. Lo feo está en el ojo del que mira, de hecho rara vez se necesita, pero el único hecho es que tanto la asignación de memoria como la creación de objetos deben estar equilibradas.
"Regular" nuevo / eliminar simplifica esto un poco al vincular la asignación de memoria y la creación de objetos, y la asignación de pila lo simplifica aún más haciendo ambos por ti.
Sin embargo, lo siguiente es perfectamente legal:
int foo() {
CBar bar;
(&bar)->~CBar();
new (&bar) CBar(42);
}
Ambos objetos se destruyen y la memoria de la pila también se recicla automáticamente. sin embargo, a diferencia de las afirmaciones de FQA, la primera llamada del destructor no está precedida por una nueva ubicación.
Sí, lo que estás haciendo es válido la mayor parte del tiempo. [basic.life]p8 dice:
Si, una vez que finaliza la vida útil de un objeto y antes de que se reutilice o libere el almacenamiento que ocupó el objeto ocupado, se creará un nuevo objeto en la ubicación de almacenamiento que ocupó el objeto original, un puntero que apunta al objeto original, una referencia que referido al objeto original, o el nombre del objeto original se referirá automáticamente al nuevo objeto y, una vez que ha comenzado la vida útil del nuevo objeto, se puede usar para manipular el nuevo objeto si:
el almacenamiento para el nuevo objeto se superpone exactamente a la ubicación de almacenamiento que ocupaba el objeto original, y
el nuevo objeto es del mismo tipo que el objeto original (ignorando los calificadores cv de nivel superior), y
el tipo del objeto original no está calificado de forma constante y, si es un tipo de clase, no contiene ningún miembro de datos no estáticos cuyo tipo esté calificado de forma constante o un tipo de referencia, y
ni el objeto original ni el nuevo objeto es un subobjeto potencialmente superpuesto ([intro.object]).
Por lo tanto, es legal si no tiene un miembro de const
o de referencia.
Si no tiene esta garantía, necesita usar std::launder
o usar el puntero que se devuelve por la nueva ubicación (como lo está haciendo de todos modos) si desea usar el nuevo objeto:
// no const/ref members
anObject->~AnObject(); // destroy object
new (anObject) AnObject(); // create new object in same storage, ok
anObject->f(); // ok
// const/ref members
anObject->~AnObject();
auto newObject = new (anObject) AnObject();
anObject->f(); // UB
newObject->f(); // ok
std::launder(anObject)->f(); // ok
Si su objeto tiene una semántica de asignación razonable (y un operador correcto =), entonces * anObject = AnObject () tiene más sentido y es más fácil de entender.
Técnicamente es una mala práctica llamar explícitamente a constructores o destructores.
La palabra clave delete termina llamándolos cuando lo usas. Lo mismo ocurre con los constructores nuevos.
Lo siento pero ese código me da ganas de arrancarme el pelo. Deberías hacerlo de esta manera:
Asignar una nueva instancia de un objeto
AnObject* anObject = new AnObject();
Eliminar una instancia de un objeto
delete anObject;
NUNCA hagas esto:
anObject->~AnObject(); // My step 1.
free(anObject)
Si debe "restablecer" un objeto, cree un método que borre todas las variables de instancia que contiene, o lo que le recomendaría que hiciera es eliminar el objeto y asignarse uno nuevo.
"¿Es el núcleo del lenguaje?"
Eso no significa nada. Perl tiene alrededor de seis formas de escribir un bucle for. El hecho de que PUEDA hacer cosas en un idioma porque son compatibles significa que debe usarlas. Heck podría escribir todo mi código usando para cambiar las declaraciones porque el "Núcleo" del lenguaje los admite. No hace que sea una buena idea.
¿Por qué estás usando malloc cuando claramente no tienes que hacerlo? Malloc es un método C
Nuevo y Eliminar son tus amigos en C ++
"Restablecer" un objeto
myObject.Reset();
Hay que ir De esta manera, evita que asigne y desasigne innecesariamente la memoria de forma peligrosa. Escriba su método Reset () para borrar el valor de todos los objetos dentro de su clase.
Tenga en cuenta que no se utilizan malloc
y free
, sino que son operator new
y operator delete
. Además, a diferencia de su código, al usar el nuevo, está garantizando una seguridad excepcional. El código casi equivalente sería el siguiente.
AnObject* anObject = ::operator new(sizeof(AnObject));
try
{
anObject = new (anObject) AnObject();
}
catch (...)
{
::operator delete(anObject);
throw;
}
anObject->~AnObject();
::operator delete(anObject)
El reinicio que está proponiendo es válido, pero no idiomático. Es difícil hacerlo bien y, como tal, generalmente está mal visto y desanimado.