[c++] ¿Por qué el uso de "nuevo" causa pérdidas de memoria?


3 Answers

Una explicación paso a paso:

// creates a new object on the heap:
new B()
// dereferences the object
*(new B())
// calls the copy constructor of B on the object
B object2 = *(new B());

Entonces, al final de esto, tiene un objeto en el montón sin puntero, por lo que es imposible de eliminar.

La otra muestra:

A *object1 = new A();

es una pérdida de memoria solo si olvida delete la memoria asignada:

delete object1;

En C ++ hay objetos con almacenamiento automático, aquellos creados en la pila, que se eliminan automáticamente, y objetos con almacenamiento dinámico, en el montón, que se asignan con new y son necesarios para liberarse con la delete . (Esto es todo más o menos)

Piensa que deberías tener una delete para cada objeto asignado con new .

EDITAR

Ahora que lo pienso, object2 no tiene que ser una pérdida de memoria.

El siguiente código es solo para hacer un punto, es una mala idea, nunca te guste un código como este:

class B
{
public:
    B() {};   //default constructor
    B(const B& other) //copy constructor, this will be called
                      //on the line B object2 = *(new B())
    {
        delete &other;
    }
}

En este caso, dado que other se pasa por referencia, será el objeto exacto señalado por el new B() . Por lo tanto, obtener su dirección por &other y borrar el puntero liberaría la memoria.

Pero no puedo enfatizar esto lo suficiente, no hagas esto. Está aquí para hacer un punto.

Question

Aprendí C # primero, y ahora estoy empezando con C ++. Según entiendo, el operador new en C ++ no es similar al que está en C #.

¿Puedes explicar el motivo de la pérdida de memoria en este código de muestra?

class A { ... };
struct B { ... };

A *object1 = new A();
B object2 = *(new B());



Es esta línea la que está goteando inmediatamente:

B object2 = *(new B());

Aquí está creando un nuevo objeto B en el montón, y luego crea una copia en la pila. El que se ha asignado en el montón ya no se puede acceder y, por lo tanto, la fuga.

Esta línea no tiene fugas de inmediato:

A *object1 = new A();

Sin embargo, si nunca object1 d object1 , habrá una pérdida.




Al crear object2 está creando una copia del objeto que creó con new, pero también está perdiendo el puntero (nunca asignado) (por lo que no hay forma de eliminarlo más adelante). Para evitar esto, tendrías que hacer object2 una referencia.




En C # y Java, usa lo nuevo para crear una instancia de cualquier clase y luego no tiene que preocuparse por destruirlo más tarde.

C ++ también tiene una palabra clave "nueva" que crea un objeto, pero a diferencia de Java o C #, no es la única forma de crear un objeto.

C ++ tiene dos mecanismos para crear un objeto:

  • automático
  • dinámica

Con la creación automática, usted crea el objeto en un entorno de ámbito: - en una función o - como miembro de una clase (o estructura).

En una función, la crearías de esta manera:

int func()
{
   A a;
   B b( 1, 2 );
}

Dentro de una clase normalmente lo crearías de esta manera:

class A
{
  B b;
public:
  A();
};    

A::A() :
 b( 1, 2 )
{
}

En el primer caso, los objetos se destruyen automáticamente cuando se sale del bloque de alcance. Esto podría ser una función o un bloque de alcance dentro de una función.

En este último caso, el objeto b se destruye junto con la instancia de A en la que es miembro.

Los objetos se asignan con nuevo cuando necesita controlar la vida del objeto y luego requiere eliminar para destruirlo. Con la técnica conocida como RAII, se ocupa de eliminar el objeto en el punto en que lo crea colocándolo dentro de un objeto automático, y espera a que el destructor del objeto automático surta efecto.

Uno de estos objetos es un shared_ptr que invocará una lógica "deleter" pero solo cuando se destruyan todas las instancias de shared_ptr que están compartiendo el objeto.

En general, aunque su código tenga muchas llamadas a nuevas, debe tener llamadas limitadas para eliminar y siempre debe asegurarse de llamarlas desde destructores o objetos "delegadores" que se colocan en punteros inteligentes.

Tus destructores tampoco deberían lanzar excepciones.

Si haces esto, tendrás pocas pérdidas de memoria.






Related