Pregunta

Como todo el mundo sabe, el Visual C++ tiempo de ejecución de las marcas no inicializado o liberado a los bloques de memoria con especial distinto de cero los marcadores.Hay alguna forma de desactivar este comportamiento completamente sin necesidad de ajustar manualmente la configuración de todos en la memoria no inicializada a los ceros?Está causando estragos con mi válido no nulos cheques, ya que 0xFEEEFEEE != 0.

Gestión de recursos humanos, tal vez debería explicar un poco mejor.Puedo crear e inicializar una variable (a través de las nuevas), y que todo va bien.Cuando me libre de ella (a través de eliminar), se establece el puntero a 0xFEEEFEEE en lugar de NULL.Al insertar una adecuada verificación de NULL, como todos los buenos programas que gestionan su propia memoria, vengo con problemas como 0xFEEEFEEE pasa un NULL comprobar sin problemas.Hay una buena manera, aparte de la configuración manual de todos los punteros a NULL cuando la eliminación de ellos, para detectar cuando la memoria ya ha sido liberada?Yo prefiero no usar Boost simplemente porque no quiero que la sobrecarga, por pequeña que sea, puesto que es la única cosa que yo estaría usando Impulso.

¿Fue útil?

Solución

No es responsabilidad de delete para restablecer todos los punteros a los objetos a NULL.También no se debe cambiar la memoria por defecto de relleno para la DEPURACIÓN de windows en tiempo de ejecución y debe usar algo como boost::shared_ptr<> para los punteros de cualquier manera.

Dicho esto, si usted realmente quiere disparar a su auto en el pie puede.

Usted puede cambio el relleno predeterminado para el windows DEPURACIÓN en tiempo de ejecución mediante el uso de un asignador de gancho como este.Esto sólo funcionará en MONTÓN asignado objeto!

int main(int argc,char** arv)
{
  // Call first to register hook    
  _CrtSetAllocHook(&zero_fill);
  // Do other stuff
  malloc(100);
}


int zero_fill(int nAllocType, 
              void* pvData, 
              size_t nSize,
              int nBlockUse, 
              long lRequest, 
              const unsigned char *szFileName, 
              int nLine )
{
  /// Very Importaint !! 
  /// infinite recursion if this is removed !!
  /// _CRT_BLOCK must not do any thing but return TRUE
  /// even calling printf in the _CRT_BLOCK will cause
  /// infinite recursion
  if ( nBlockUse == _CRT_BLOCK )
    return( TRUE );
  switch(nAllocType)
  {
  case _HOOK_ALLOC:
  case _HOOK_REALLOC:
    // zero initialize the allocated space.
    memset(pvData,0,nSize);
    break;
  case _HOOK_FREE:
    break;
  }
  return TRUE;
}

Otros consejos

Cuando se crea un puntero, explícitamente al inicializar a NULL.Asimismo, después de un delete.Dependiendo del valor de datos sin inicializar (excepto en algunos casos específicos) está pidiendo problemas.

Usted puede ahorrar un montón de dolores de cabeza por el uso de un puntero inteligente de la clase (tales como boost::shared_ptr) que automáticamente lidiar con el hecho de que un puntero es inicializado o no.

VC++comportamiento no debería causar estragos con cualquier válido compruebe que puede hacer.Si usted está viendo la 0xfeeefeee, a continuación, usted no ha escrito a la memoria (o se han liberado, por lo que no debería ser de lectura de la memoria, de todos modos.

Si estás leyendo sin inicializar la memoria, los controles son más ciertamente no es "válido".Se libera la memoria.Es posible que ya esté en uso para algo más.Usted no puede hacer ninguna hipótesis sobre el contenido de la memoria no inicializada en C/C++.

Java y C#, creo) se garantiza que la memoria asignada es puesta a cero antes de su uso, y, por supuesto, la recolección de basura no te deja ver la memoria liberada en absoluto.Pero eso no es una propiedad de la C montón, lo que expone a la memoria directamente.

Si se construye en modo de Lanzamiento en lugar de en modo de Depuración, el tiempo de ejecución no se llene la memoria no inicializada en todo, pero todavía no será ceros.Sin embargo, usted debe no dependen de este comportamiento, debe explícitamente inicializar la memoria con memset(), ZeroMemory(), o SecureZeroMemory(), o establecer una marca en algún lugar que indica que la memoria está todavía no se ha inicializado.La lectura de la memoria sin inicializar va a resultar en un comportamiento indefinido.

Usted dice:

Puedo crear e inicializar una variable (a través de las nuevas), y que todo va bien.Cuando me libre de ella (a través de eliminar), se establece el puntero a 0xFEEEFEEE en lugar de NULL.Al insertar una adecuada verificación NULL, como todos los buenos programas que gestionan su propia memoria, vengo con problemas como 0xFEEEFEEE pasa un NULO cheque sin problemas.

Incluso el montón de depuración de las rutinas de MSVC no va a cambiar el valor de la puntero vas a eliminar - el valor del puntero va a eliminar no va a cambiar (incluso a NULL).Suena como que usted está accediendo a un puntero que pertenece el objeto que ha acaba de eliminar, lo cual es un error, simple y sencillo.

Estoy bastante seguro de que lo que estamos tratando de hacer simplemente cubrir un inválido de acceso a la memoria.Usted debe publicar un fragmento de código que nos muestran lo que realmente está sucediendo.

@Jeff Hubbard (comentario):

En realidad, esto inadvertidamente me da con la solución que yo quiero:Yo puedo pvData a NULL en _HOOK_FREE y no tener problemas con 0xFEEEFEEE para mi puntero de dirección.

Si este es el trabajo para usted, entonces significa que usted está leyendo la memoria liberada cuando tienes que probar para el puntero NULO (es decir, el puntero se encuentra en la memoria de la libertad).

Esto es un error.

La 'solución' que usted está utilizando es simplemente ocultar, no corregir, el error.Cuando libera la memoria que alguna vez se asigna a otra cosa, de repente usted estará usando el valor incorrecto como un puntero a la cosa equivocada.

Que en realidad es una característica muy agradable en VC++ (y creo que otros compiladores), ya que permite ver sin asignar memoria para un puntero en el depurador.Voy a pensar dos veces antes de desactivar esa funcionalidad.Cuando se elimina un objeto en C++ debe establecer el puntero a NULL en caso de que algo más tarde intenta eliminar el objeto de nuevo.Esta característica le permite detectar los lugares donde olvidó poner el puntero a NULL.

Si está trabajando en modo de lanzamiento, es debido a la cizalladura de la suerte.

Mike B es correcto asumir que la depuración de revisión se esconde un error.En modo de lanzamiento, que es un puntero, que ha sido liberado pero no se ponen a NULL, y la memoria que apunta es todavía "válido".En algún momento en el futuro, las asignaciones de memoria de cambiar, o de la imagen de la memoria va a cambiar, o algo que hará que el "válida" bloque de memoria para convertirse en "no válido".En ese momento, su versión de lanzamiento va a comenzar a fallar.La conmutación al modo de depuración para encontrar el problema será inútil, porque el modo de depuración ha sido "corregido".

Creo que hacemos un llamamiento a todos de acuerdo en que el código siguiente no vas a trabajar.

char * p = new char[16];     // 16 bytes of random trash
strcpy(p, "StackOverflow");  // 13 characters, a '\0' terminator, and two bytes of trash
delete [] p;                 // return 16 bytes to the heap, but nothing else changes;

if (p != NULL)               // Why would p be NULL?  It was never set to NULL
    ASSERT(p[0] == 'S');     // In debug, this will crash, because p = 0xfeeefeee and 
                             // dereferencing it will cause an error.
                             // Release mode may or may or may not work, depending on
                             // other memory operations

Como casi todos los demás cartel ha dicho, los punteros se debe establecer para NULL después de llamar a delete.Si lo hace usted mismo o usar el boost o algún otro contenedor o incluso la macro en este hilo es para usted.

Lo que pasa es que mi código se bloquea bajo una depuración de compilación, pero logra en virtud de una versión de compilación.

Compilación de la versión se colgará en la máquina del cliente.Siempre lo hace.

Yo he comprobado con un depurador y mi punteros se establece 0xFEEEFEEE después de que me llame a eliminar en ellos.

Los punteros no se cambió después de que usted llame a eliminar en ellos.Es la memoria que punto a que se pone en 0xfeeefeee, 0xfeeefeee, ..., 0xfeeefeee.

Si usted descubre que su programa lee los datos de la memoria liberada (que está muy bien indicado por 0xfeeefeee patrón en la generación de DEPURACIÓN), que tiene un bug.

@[Jeff Hubbard]:

Lo que pasa es que mi código se bloquea en virtud de una depuración de la compilación, pero que lo logra en virtud de una versión de compilación.Yo he comprobado con un depurador y mi punteros se establece 0xFEEEFEEE después de que me llame a eliminar en ellos.De nuevo, el mismo código de liberación no se cuelga y se comporta como se espera.

Esto es muy extraño comportamiento - todavía estoy convencido de que probablemente hay una latente error que está siendo ocultado por el _CrtSetAllocHook() solución.

El 0xFEEEFEEE la firma es utilizada por el sistema operativo administrador del montón para indicar que la memoria liberada (véase http://www.nobugs.org/developer/win32/debug_crt_heap.html).Por casualidad puedes publicar algunos de reproducción del código y de indicar exactamente que versión de compilador usas?

Estoy bastante seguro de que no se puede deshabilitar el visual studio por defecto aquí, e incluso si lo hizo, el valor sería entonces justo lo que estaba en la memoria antes de que la memoria se asigna.

Su mejor acaba de conseguir en el hábito de establecer a 0 en el primer lugar, sólo 2 extra charecters.

int *ptr=0;

También puede utilizar la macro NULL, que se define como 0 (pero no de manera predeterminada, por lo que ser cuidadoso con múltiples definiciones cuando includeing cosas como windows.h y la definición de ti mismo!

si usted está usando malloc, no inicializar la memoria para nada.usted obtener lo que sea.si desea asignar un bloque y se inicializa a 0, el uso de 'calloc', que es como malloc sólo con la inicialización (un tamaño de elemento de parámetro que se establece en 1 si desea emular malloc).usted debe leer sobre calloc antes de usarlo ya que tiene algunas ligeras diferencias.

http://wiki.answers.com/Q/What_is_the_difference_between_malloc_and_calloc_functions

¿Por qué no crear tu propio #definir y conseguir en el hábito de usar?

I. e.

#define SafeDelete(mem) { delete mem; mem = NULL; }
#define SafeDeleteArray(mem) { delete [] mem; mem = NULL; }

Obviamente, usted puede poner el nombre que desees.deleteZ, deletesafe, lo que estás cómodo con.

Usted puede crear un administrador de memoria de también.Entonces usted podría anular new y delete para tirar de/volver a poner un pre asignados chuck de la memoria.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top