2010-03-09 14 views
7

siguiendo una discusión en una reunión de software que he establecido para averiguar si eliminar una matriz de primitivas dinámicamente asignadas con delete llano causará una pérdida de memoria.¿Eliminar p, donde p es un puntero a la matriz siempre una pérdida de memoria?

He escrito este pequeño programa y compilado con Visual Studio 2008 que se ejecuta en Windows XP:

#include "stdafx.h" 
#include "Windows.h" 

const unsigned long BLOCK_SIZE = 1024*100000; 
int _tmain() 
{ 
    for (unsigned int i =0; i < 1024*1000; i++) 
    { 
     int* p = new int[1024*100000]; 
     for (int j =0;j<BLOCK_SIZE;j++) p[j]= j % 2; 
     Sleep(1000); 
     delete p; 
    } 
} 

I que monitoriza el consumo de memoria de mi solicitud usando el administrador de tareas, es sorprendente que la memoria se asigna y se liberó correctamente , memoria asignada no aumentó de manera constante como se esperaba

he modificado mi programa de pruebas para asignar una matriz de tipo primitivo no:

#include "stdafx.h" 
#include "Windows.h" 


struct aStruct 
{ 
    aStruct() : i(1), j(0) {} 

    int i; 
    char j; 
} NonePrimitive; 

const unsigned long BLOCK_SIZE = 1024*100000; 
int _tmain() 
{ 
    for (unsigned int i =0; i < 1024*100000; i++) 
    { 
     aStruct* p = new aStruct[1024*100000]; 
     Sleep(1000); 
     delete p; 

    } 
} 

después de ejecutar durante 10 minutos no hubo un aumento significativo en la memoria

Compilé el proyecto con el nivel de advertencia 4 y no recibí ninguna advertencia.

¿es posible que el tiempo de ejecución del estudio visual realice un seguimiento de los tipos de objetos asignados para que no haya diferente entre delete y delete[] en ese entorno?

+0

¿Duplicado? http://stackoverflow.com/questions/1913343/how-could-pairing-new-with-delete-possibly-lead-to-memory-leak-only –

+0

@Philip Potter: No de esa misma pregunta, esa es específicamente acerca de causar una pérdida de memoria. Y la pérdida de memoria no es típica en este caso. – sharptooth

+0

Pruébalo con una matriz de 'shared_ptr ', cada uno apuntando a una int diferente asignada, y verás si tu implementación está haciendo 'delete' y' delete [] 'equivalent. Siempre esta fascinación en C++ con cosas que las personas saben que están equivocadas, están claramente establecidas en el estándar como incorrectas, y que a pesar de todo parecen como si a veces funcionaran ;-) –

Respuesta

19

eliminar p, donde p es una matriz se denomina comportamiento indefinido.

Específicamente, cuando asigna una matriz de tipos de datos sin procesar (ints), el compilador no tiene mucho trabajo que hacer, por lo que lo convierte en un malloc() simple, por lo que eliminar p probablemente funcione.

borrado p va a fracasar, por lo general, cuando:

  • p era un tipo de datos - Eliminar p; no sabrá llamar a destructores individuales.
  • un "usuario" sobrecarga el operador nuevo [] y elimina [] para usar un montón diferente al montón normal.
  • el tiempo de ejecución de depuración sobrecarga el operador nuevo [] y elimina [] para agregar información de seguimiento adicional para la matriz.
  • el compilador decide que necesita almacenar información RTTI adicional junto con el objeto, que elimina p; no entenderá, pero eliminará [] p; será.
17

No, es un comportamiento indefinido. No lo haga - use delete[].

En VC++ 7 a 9 funciona when the type in question has trivial destructor, pero podría dejar de funcionar en las versiones más recientes, lo que normalmente es un comportamiento indefinido. No lo hagas de todos modos.

+0

Buena explicación de por qué podría ¡Funciona en el caso de @ Eli! –

2

no, usted debe utilizar delete[] cuando se trata de matrices

3

Se llama comportamiento indefinido; podría funcionar, pero no sabes por qué, así que no debes seguir con eso.

No creo que Visual Studio realice un seguimiento de cómo asignó los objetos, como matrices u objetos simples, y mágicamente agrega [] a su eliminación. Probablemente compila delete p; con el mismo código que si lo asignó con p = new int y, como dije, por alguna razón funciona. Pero no sabes por qué.

2

Simplemente usando delete no llamará a los destructores de los objetos en la matriz. Mientras que posiblemente funcione como está previsto, no está definido ya que existen algunas diferencias en cómo funcionan exactamente. Entonces no debes usarlo, even for built in types.

+0

las preguntas frecuentes tienen un argumento muy fuerte, gracias por señalarlo – Eli

1

Parece que la razón para no perder memoria es que la eliminación se basa normalmente en libre, que ya sabe cuánta memoria necesita para liberar. Sin embargo, es poco probable que la parte de C++ se limpie correctamente. Apuesto a que solo se llama el destructor del primer objeto.

1

El uso de delete with [] le dice al compilador que llame al destructor en cada elemento de la matriz. No usar delete [] puede causar pérdidas de memoria si se utiliza en una gran variedad de objetos que utilizan las asignaciones de memoria dinámica como sigue:

class AClass 
{ 
public: 
    AClass() 
    { 
     aString = new char[100]; 
    } 
    ~AClass() 
    { 
     delete [] aString; 
    } 
private: 
    const char *aString; 
}; 

int main() 
{ 
    AClass * p = new AClass[1000]; 
    delete p; // wrong 
    return 0; 
} 
3

Una respuesta es que sí, puede causar pérdidas de memoria, ya que no llama el destructor para cada elemento en la matriz. Eso significa que cualquier memoria adicional propiedad de elementos en la matriz se fugará.

La respuesta más conforme a los estándares es que es un comportamiento indefinido. El compilador, por ejemplo, tiene todo el derecho de usar diferentes grupos de memoria para matrices que para elementos que no son de matriz. Hacer la nueva forma pero borrar la otra podría causar daños en el montón.

Su compilador puede hacer garantías de que el estándar no, pero el primer problema persiste. Para artículos POD que no poseen memoria adicional (o recursos como manejadores de archivos) puede estar bien.

Incluso si es seguro para su compilador y elementos de datos, no lo haga de todos modos, también es engañoso para cualquiera que intente leer su código.

Cuestiones relacionadas