Por el contrario, siempre debe preferir las asignaciones de pila, en la medida en que, como regla general, nunca debe tener nuevo / eliminar en su código de usuario.
Como dice, cuando la variable se declara en la pila, su destructor se llama automáticamente cuando sale del alcance, que es su herramienta principal para rastrear la vida útil de los recursos y evitar fugas.
Entonces, en general, cada vez que necesite asignar un recurso, ya sea memoria (llamando a new), manejadores de archivos, sockets o cualquier otra cosa, envuélvalo en una clase donde el constructor adquiere el recurso y el destructor lo libera. Luego, puede crear un objeto de ese tipo en la pila y tiene la garantía de que su recurso se liberará cuando salga del alcance. De esa manera, no tiene que rastrear sus pares nuevos / eliminados en todas partes para asegurarse de evitar pérdidas de memoria.
El nombre más común para este modismo es RAII
También busque las clases de punteros inteligentes que se utilizan para ajustar los punteros resultantes en los raros casos en los que tiene que asignar algo nuevo fuera de un objeto RAII dedicado. En su lugar, pasa el puntero a un puntero inteligente, que luego rastrea su vida útil, por ejemplo, mediante el conteo de referencias, y llama al destructor cuando la última referencia sale del alcance. La biblioteca estándar tiene std::unique_ptr
una gestión sencilla basada en el alcance y std::shared_ptr
que hace referencia al recuento para implementar la propiedad compartida.
Muchos tutoriales demuestran la creación de instancias de objetos utilizando un fragmento como ...
Entonces, lo que has descubierto es que la mayoría de los tutoriales apestan. ;) La mayoría de los tutoriales le enseñan pésimas prácticas de C ++, incluida la llamada a new / delete para crear variables cuando no es necesario, y le dificulta el seguimiento de la vida útil de sus asignaciones.
Aunque tener cosas en la pila puede ser una ventaja en términos de asignación y liberación automática, tiene algunas desventajas.
Es posible que no desee asignar objetos grandes en la pila.
Despacho dinámico! Considere este código:
Esto imprimirá "B". Ahora veamos qué sucede cuando se usa Stack:
Esto imprimirá "A", que puede no ser intuitivo para aquellos que están familiarizados con Java u otros lenguajes orientados a objetos. La razón es que ya no tiene un puntero a una instancia de
B
. En su lugar,B
se crea una instancia de y se copia en laa
variable de tipoA
.Algunas cosas pueden suceder de forma poco intuitiva, especialmente cuando es nuevo en C ++. En C tienes tus punteros y eso es todo. Sabes cómo usarlos y SIEMPRE hacen lo mismo. En C ++ este no es el caso. Imagínese lo que sucede, cuando se utiliza una en este ejemplo como un argumento a favor de un método - las cosas se complican y se hace una gran diferencia si
a
es de tipoA
oA*
inclusoA&
(llamada por referencia). Son posibles muchas combinaciones y todas se comportan de manera diferente.fuente
Bueno, la razón para usar el puntero sería exactamente la misma que la razón para usar punteros en C asignados con malloc: ¡si quieres que tu objeto viva más tiempo que tu variable!
Incluso es muy recomendable NO utilizar el nuevo operador si puede evitarlo. Especialmente si usa excepciones. En general, es mucho más seguro dejar que el compilador libere sus objetos.
fuente
He visto este anti-patrón en personas que no obtienen el operador & address-of. Si necesitan llamar a una función con un puntero, siempre asignarán en el montón para que obtengan un puntero.
fuente
Trate el montón como un bien inmueble muy importante y utilícelo con mucho cuidado. La regla básica es usar stack siempre que sea posible y usar heap siempre que no haya otra forma. Al asignar los objetos en la pila, puede obtener muchos beneficios, como:
(1). No necesita preocuparse por desenrollar la pila en caso de excepciones
(2). No necesita preocuparse por la fragmentación de la memoria causada por la asignación de más espacio del necesario por parte de su administrador de almacenamiento dinámico.
fuente
La única razón por la que me preocuparía es que Dog ahora está asignado en la pila, en lugar de en el montón. Entonces, si Dog tiene un tamaño de megabytes, es posible que tenga un problema,
Si necesita ir por la ruta nueva / eliminar, tenga cuidado con las excepciones. Y debido a esto, debe usar auto_ptr o uno de los tipos de puntero inteligente boost para administrar la vida útil del objeto.
fuente
No hay razón para ser nuevo (en la pila) cuando puede asignar en la pila (a menos que por alguna razón tenga una pila pequeña y quiera usar la pila.
Es posible que desee considerar el uso de shared_ptr (o una de sus variantes) de la biblioteca estándar si desea realizar una asignación en el montón. Eso se encargará de hacer la eliminación una vez que todas las referencias al shared_ptr hayan dejado de existir.
fuente
Hay una razón adicional, que nadie más ha mencionado, por la que puede optar por crear su objeto de forma dinámica. Los objetos dinámicos basados en montones le permiten hacer uso del polimorfismo .
fuente
Tuve el mismo problema en Visual Studio. Tienes que usar:
yourClass-> classMethod ();
más bien que:
yourClass.classMethod ();
fuente