2010-02-27 23 views
6

Si hago esto:¿Cómo se diferencia la eliminación entre los tipos de datos incorporados y los definidos por el usuario?

// (1.) 
int* p = new int; 
//...do something 
delete p; 

// (2.) 
class sample 
{ 
public: 
sample(){} 
~sample(){} 
}; 
sample* pObj = new sample; 
//...do something 
delete pObj; 

Entonces, ¿cómo compilador de C++ saben que delete siguiente objeto se encuentra incorporado el tipo de datos o un objeto de clase?

Mi otra pregunta es que si new un puntero a un array de int 's y luego delete [] entonces ¿cómo sabe el compilador el tamaño de bloque de memoria para desasignar?

Respuesta

4
  1. el compilador sabe el tipo de punta-a-objeto porque no conoce el tipo del puntero:

    • p es un int*, por lo tanto, al cual apunta al objeto será un int.
    • pObj es un sample*, por lo tanto, el objeto apuntado será un sample.
  2. El compilador no saben si sus int* p puntos a un solo objeto o int a una matriz (int[N]). Es por eso que usted debe recordar usar delete[] en lugar de delete para arreglos.

    El tamaño del bloque de memoria para desasignar y, lo que es más importante, el número de objetos para destruir, se conocen porque new[] los almacena en algún lugar, y delete[] sabe dónde recuperar estos valores. This question from C++ FAQ Lite muestra dos técnicas comunes para implementar new[] y delete[].

4

Conoce la diferencia entre ellos por el tipo de puntero que le pasa: es un comportamiento indefinido pasar un tipo de puntero diferente del asignado (excepto que puede pasar un puntero a una clase base, si el destructor es virtual, por supuesto).

El tamaño de una matriz se almacenará en algún lugar. Es como en C donde puede malloc una cierta cantidad de memoria, y libre después - el tiempo de ejecución tendrá que administrar para saber el tamaño asignado previamente.

Por ejemplo, puede almacenar el recuento de elementos antes del búfer asignado. El estándar permite explícitamente al compilador pasar un tamaño de solicitud diferente a la función de asignación (operator new[]) en el caso de asignaciones de matriz; esto puede ser utilizado por el compilador para ingresar el conteo y compensar la dirección devuelta por la expresión new por el tamaño de ese contador.

1

¡No es así!

Todo lo que hace delete es que invoca el destructor del tipo, que es "no acción" en el caso de los tipos primitivos. Luego, pasa el puntero a ::operator delete (o una versión sobrecargada si lo desea), y el operador devuelve la memoria (un problema del administrador de memoria). es decir, puede escribir su propio administrador de memoria fácilmente en C++ si lo desea, ¡el idioma lo proporciona de manera predeterminada!

1
  1. el compilador sabe el tipo del objeto que se borra y escribe código diferente para usted para lograr los resultados deseados:
    • eliminar p puede llamar al eliminar el tiempo de ejecución con el tamaño de un int.
    • delete pObj puede llamar pObj-> ~ muestra() en primer lugar, a continuación, elimine con el tamaño de la muestra
  2. Creo que con matrices, hay un valor oculto para el tamaño de la matriz, por lo que podría ser que toda la matriz se elimina de una vez.
1

Entonces, ¿cómo sabe el compilador de C++ ese objeto siguiente de eliminación se ha incorporado en el tipo de datos o un objeto de clase?

Porque en tiempo de compilación el compilador rastrea los tipos de cada objeto y planta el código apropiado.

Mi otra pregunta es que si actualizo un puntero a una matriz de int y luego elimino [], ¿cómo sabe el compilador el tamaño del bloque de memoria para desasignar?

No lo es.El sistema de tiempo de ejecución lo sigue de cerca.
Cuando dinámicamente asigna una matriz, la biblioteca de tiempo de ejecución asocia el tamaño del objeto con el objeto, por lo tanto, cuando lo elimina sabe (al buscar el valor asociado) el tamaño.

Pero supongo que quieres saber cómo funciona la asociación?
Esto depende del sistema y es un detalle de implementación. Pero una estratagema simple es asignar un espacio adicional de 4 bytes para almacenar el tamaño en los primeros cuatro bytes y luego devolver un puntero al 4to byte asignado. Cuando elimina un puntero, sabe que el tamaño es de 4 bytes antes del puntero. Nota: No estoy diciendo que su sistema esté usando esta técnica, pero es una estratagema.

0

Para la primera parte (no es un array) de la pregunta, las respuestas anteriores indicando que el compilador inserta código para desasignar el número apropiado de bytes en función del tipo de puntero, no bastante proporcionan una respuesta clara para mí ... el operador delete 1) llama a un destructor si corresponde y luego 2) llama a la función "operator delete()" ... es la eliminación del operador la que realmente desasigna. Puedo ver que el código generado por el compilador desempeña un papel en la parte (1), es decir. la dirección de destino del destructor debe ser insertada. Pero en la parte (2), es una función de biblioteca preexistente que maneja la desasignación, entonces, ¿cómo sabrá el tamaño de los datos? El operador global delete - que, creo que se usa en todos los casos, a menos que el programador defina una versión global de clase/miembro sobrecargado - acepta solo un argumento nulo * que especifica el inicio de los datos, por lo que puede incluso se aprobó el tamaño de los datos. He leído cosas que indican la idea del código generado por el compilador, así como cosas que sugieren que la eliminación del operador global para no arrays simplemente usa free(), es decir. conoce el tamaño de los datos no por el tipo de puntero, sino por mirar unos pocos bytes antes de los datos, donde el tamaño habrá sido guardado por new/malloc. Esta última es la única solución que tiene sentido para mí, pero tal vez alguien me puede aclarar de manera diferente ...

Cuestiones relacionadas