2009-07-29 8 views
7

¿Por qué este código no no causa pérdidas de memoria?std :: auto_ptr, delete [] y fugas

int iterCount = 1000; 
int sizeBig = 100000; 
for (int i = 0; i < iterCount; i++) 
{ 
    std::auto_ptr<char> buffer(new char[sizeBig]); 
} 

WinXP SP2, Compilador: BCB.05.03

+0

En la mayoría de los casos, si empareja nuevo con delete [] y viceversa para tipos no triviales, esto no provoca una fuga, en su lugar, el programa simplemente se bloquea al intentar desasignar la memoria. – sharptooth

+3

Puede intentar usar boost :: scoped_array en lugar de std :: auto_ptr –

Respuesta

15

Porque eres (des) afortunado. auto_ptr llamadas delete, no delete []. Este es un comportamiento indefinido.

trate de hacer algo como esto y ver si le da la misma suerte:

struct Foo 
{ 
    char *bar; 
    Foo(void) : bar(new char[100]) { } 
    ~Foo(void) { delete [] bar; } 
} 

int iterCount = 1000; 
int sizeBig = 100000; 
for (int i = 0; i < iterCount; i++) 
{ 
    std::auto_ptr<Foo> buffer(new Foo[sizeBig]); 
} 

La idea aquí es que su destructor para Foo no será llamado.


La razón es algo como esto: Cuando dice delete[] p, la implementación de delete[] se supone que debe ir a cada elemento de la matriz, llame a su destructor, a continuación, liberar la memoria a la que apunta p. De manera similar, se supone que delete p llama al destructor en p, luego libera la memoria.

char 's no tienen un destructor, por lo que solo va a eliminar la memoria apuntada por p. En mi código anterior, es no va a destruir cada elemento en la matriz (porque no está llamando al delete[]), por lo que algunos Foo dejarán su barra de variables locales sin eliminar.

+0

Sí, tengo mala suerte :) Gracias por su explicación. – Xeningem

+0

Compilé esto pero recibo el mensaje de error '_BLOCK_TYPE_IS_VALID (pHead-> nBlockUse)', el programa falla.esto parece indicar que se está borrando dos veces, pero no sé cómo podría suceder – zar

+0

El destructor de 'Foo' se llamaría de hecho' iterCount'times, pero ten en cuenta 'iterCount' *' sizeBig' times – zar

3

auto_ptr solo vivirá durante la iteración del ciclo y liberará el objeto conectado al finalizar la iteración.

El compilador puede ver que en este caso nueva [] puede asignar espacio de la misma manera como nueva - sin almacenar el número de elementos en cualquier lugar ya que no hay necesidad de llamar trivial char destructores - y por eso más tarde cuando eliminar es llamado por destructor del auto_ptr en lugar de delete [] no causa problemas ya que el bloque de memoria en realidad se ha asignado en la nueva forma 's y que la asignación puede ser emparejado con borrar.

Este es un ejemplo de una cosa que no se debe hacer. Depende del compilador decidir si reemplaza nuevo [] con nuevo. Utilizando borre en lugar de delete [] y viceversa es un comportamiento indefinido.

Ver Why would you write something like this? (intentionally not using delete [] on an array) para la discusión de eliminar vs delete [].

+0

Así que como dice GMan: es pura suerte * eliminar * es equivalente a * eliminar [] * aquí? – xtofl

+1

Bueno, sí, es el resultado de que el compilador intenta ser astuto y guardar accidentalmente al desarrollador. – sharptooth

+3

No es un resultado de que el compilador sea inteligente, es más bien el resultado de que el compilador es flojo y hace lo más fácil (lo que en este caso significa que la asignación de memoria para un elemento y matriz cuando los POD están involucrados funciona exactamente igual). Por supuesto, esto es U.B., así que es "pura suerte" que funcione en una implementación determinada, y IIRC hay algunas implementaciones reales en las que no funciona. –