2010-05-24 15 views
9

Tengo una muy simple código C++ aquí: (. Violación de Acceso)La eliminación de punteros borrados siempre da como resultado una Infracción de acceso?

char *s = new char[100]; 
strcpy(s, "HELLO"); 
delete [] s; 
int n = strlen(s); 

Si funciono el código de Visual C++ 2008 pulsando F5 (Iniciar depuración,) este siempre resulta en accidente Sin embargo, a partir este ejecutable fuera del IDE, o usando el del IDE Ctrl + F5 (Inicio sin depuración) no causa ningún bloqueo. ¿Cuál podría ser la diferencia?

También quiero saber si es posible reproducir de forma estable el bloqueo de infracción de acceso causado por el acceso al área eliminada. ¿Es este tipo de choque raro en la vida real?

+3

Produce un comportamiento indefinido, lo que significa que el programa puede hacer lo que quiera. Sin embargo, es un poco extraño que no se cuelgue fuera del depurador. ¿Qué sucede realmente? Si se trata de un programa de consola, ¿cuál es el resultado? –

+3

Cuidar los indicadores borrados es realmente un problema. Es por eso que debería usar 'std :: vector' o en este caso particular' std :: string' en lugar de 'new []'. Nunca deberías tener que usar 'delete'. – avakar

+0

El ejemplo de código es un recorte de la aplicación real. Estoy reproduciendo un error que rara vez ocurre, probablemente solo cuando un hilo hace el 'eliminar' y otro hace la desreferencia. Por lo tanto, quiero una forma estable de reproducir esto. Y SO no me falló con todas estas útiles respuestas :) – Gant

Respuesta

16

El acceso a la memoria a través de un puntero eliminado es un comportamiento indefinido. No puede esperar ningún comportamiento confiable/repetible.

Lo más probable es que "funcione" en el primer caso porque la cadena todavía está "sentada allí" en la memoria disponible ahora - = pero no puede confiar en eso. VS llena la memoria con valores de depuración para ayudar a forzar los bloqueos para ayudar a encontrar estos errores.

5

Desreferenciar un puntero después delete es un comportamiento indefinido - puede pasar cualquier cosa, incluyendo pero no limitado a:

  • de corrupción de datos
  • acceso violación
  • no hay efectos visibles

resultados exactos dependerá de múltiples factores la mayoría de los cuales están fuera de tu control. Será mejor que no desencadene un comportamiento indefinido en primer lugar.

2

Normalmente, no hay diferencia en la memoria asignada y liberada desde la perspectiva del proceso. Por ejemplo, el proceso solo tiene un mapa de memoria grande que crece según demanda.

La violación de acceso es causada por la memoria de lectura/escritura que no está disponible, por lo general no se busca en el proceso. Varias utilidades de depuración de memoria de tiempo de ejecución utilizan el mecanismo de búsqueda para rastrear accesos de memoria no válidos sin la grave penalización de tiempo de ejecución que tendría la comprobación de memoria de software.

De todos modos, su ejemplo solo demuestra que a veces se detecta un error al ejecutar el programa en un entorno, pero no se detecta en otro, pero sigue siendo un error y el comportamiento del código anterior no está definido.

8

La diferencia es que un depurador y bibliotecas de depuración, y el código construido en modo "depuración", le gusta romper cosas que deberían romperse. Su código debe romperse (porque accede a la memoria que técnicamente ya no posee), por lo que se rompe más fácilmente cuando se compila para la depuración y se ejecuta en el depurador.

En la vida real, generalmente no se recibe un aviso tan poco sutil. Todas esas cosas que hacen que las cosas se rompan cuando deberían en el depurador ... esas cosas son caras. Por lo tanto, no se revisa estrictamente en versión. Es posible que 99 de cada 100 veces se salgan con la libertad de liberar algo de memoria y acceder a ella inmediatamente después, porque las bibliotecas de tiempo de ejecución no siempre devuelven la memoria al sistema operativo de inmediato. Pero esa centésima vez, o la memoria se ha ido, u otro hilo lo posee ahora y está obteniendo la longitud de una cuerda que ya no es una cadena, sino una matriz de basura de 252462649 bytes que corre de frente a sin asignar (y por lo tanto no- existente, en cuanto a usted o el tiempo de ejecución debería importar) memoria. Y no hay casi nada para decirte lo que acaba de pasar.

Así que no hagas eso. Una vez que haya eliminado algo, considérelo muerto y desaparecido. O perderás la mitad de tu vida rastreando heisenbugs.

+0

Buena referencia a heisenbugs: D –

1

El ejecutable con símbolos de depuración es capaz de detectar algunos casos de violaciones de acceso. El código para detectar esto está contenido en el ejecutable, pero no se activará de manera predeterminada.

Aquí encontrará una explicación de cómo se puede controlar el comportamiento fuera de un depurador: http://msdn.microsoft.com/en-us/library/w500y392%28v=VS.80%29.aspx

1

También me gustaría saber si es posible para reproducir de forma estable el accidente acceso Violación causado accedan área eliminada?

En lugar de simplemente delete, podría considerar el uso de una función en línea que también establece el valor del puntero eliminado en 0/NULL. Esto generalmente se bloqueará si lo referencia. Sin embargo, no se quejará si lo elimina por segunda vez.

¿Este tipo de accidente es raro en de la vida real?

No, este tipo de bloqueo probablemente esté detrás de la mayoría de los bloqueos que usted y yo vemos en el software.

Cuestiones relacionadas