studio programacion para móviles libro edición desarrollo desarrollar curso aprende aplicaciones c++ pointers dynamic-memory-allocation delete-operator

c++ - para - manual de programacion android pdf



¿Por qué se bloquea mi programa cuando incremente un puntero y luego lo elimine? (4)

Estaba resolviendo algunos ejercicios de programación cuando me di cuenta de que tengo un gran malentendido sobre los punteros. Por favor, podría alguien explicar el motivo por el cual este código causa un bloqueo en C ++.

#include <iostream> int main() { int* someInts = new int[5]; someInts[0] = 1; someInts[1] = 1; std::cout << *someInts; someInts++; //This line causes program to crash delete[] someInts; return 0; }

PD: Soy consciente de que no hay ninguna razón para usar "nuevo" aquí, solo estoy haciendo el ejemplo lo más pequeño posible.


¡De hecho, la declaración posterior a la que marca como causante del bloqueo del programa hace que el programa falle!

Debe pasar el mismo puntero para delete[] medida que obtiene de new[] .

De lo contrario, el comportamiento del programa no está definido .


El problema es que con los someInts++; está pasando la dirección del segundo elemento de una matriz a su declaración delete[] . Debe pasar la dirección del primer elemento (original):

int* someInts = new int[5]; int* originalInts = someInts; // points to the first element someInts[0] = 1; someInts[1] = 1; std::cout << *someInts; someInts++; // points at the second element now delete[] originalInts;


Puede incrementar un puntero dentro del bloque y usar ese puntero incrementado para acceder a diferentes partes del bloque, eso está bien.

Sin embargo, debe pasar Eliminar el puntero que obtuvo de Nuevo. No es una versión incrementada de ella, no es un puntero que fue asignado por algún otro medio.

¿Por qué? Bueno, la respuesta de escape es porque eso es lo que dice el estándar.

La respuesta práctica es porque para liberar un bloque de memoria, el administrador de memoria necesita información sobre el bloque. Por ejemplo, dónde comienza y termina, y si los trozos adyacentes son gratuitos (normalmente un administrador de memoria combinará trozos libres adyacentes) y a qué ámbito pertenece (importante para bloquear en los administradores de memoria multihilo).

Esta información generalmente se almacena inmediatamente antes de la memoria asignada. El administrador de memoria restará un valor fijo de su puntero y buscará una estructura de metadatos de asignación en esa ubicación.

Si pasa un puntero que no apunta al inicio de un bloque de memoria asignada, entonces el administrador de memoria intenta realizar la resta y leer su bloque de control, pero lo que termina leyendo no es un bloque de control válido.

Si tiene suerte, el código se bloquea rápidamente, si no tiene suerte, puede terminar con una corrupción sutil de la memoria.


Sin entrar en los detalles de una implementación específica aquí, la razón intuitiva detrás del colapso se puede explicar simplemente considerando lo que se supone que debe hacer delete[] :

Destruye una matriz creada por una new[] -expresión

Le das a delete[] un puntero a una matriz. Entre otras cosas, tiene que liberar la memoria que asignó para mantener el contenido de esa matriz después.

¿Cómo sabe el asignador qué liberar? Utiliza el puntero que le dio como clave para buscar la estructura de datos que contiene la información de contabilidad para el bloque asignado. En algún lugar, hay una estructura que almacena la asignación entre los punteros a los bloques previamente asignados y la operación de contabilidad asociada.

Puede desear que esta búsqueda genere algún tipo de mensaje de error amistoso si el puntero que pasa a delete [] no fue devuelto por un new[] correspondiente, pero no hay nada en el estándar que lo garantice.

Entonces, es posible, dado un puntero que no había sido previamente asignado por new[] , delete[] termina mirando algo que realmente no es una estructura de contabilidad consistente. Los cables se cruzan. Se produce un choque.

O bien, es posible que desee que delete[] diga "hey, parece que este puntero apunta a algún lugar dentro de una región asignada anteriormente. Déjeme regresar y encontrar el puntero que devolví cuando asigné esa región y usar eso para buscar la información de contabilidad "pero, una vez más, no hay tal requisito en la norma:

Para la segunda forma (matriz), la expresión debe ser un valor de puntero nulo o un valor de puntero obtenido previamente por una forma de matriz de nueva expresión. Si la expresión es cualquier otra cosa , incluso si es un puntero obtenido por la forma no-matriz de nueva-expresión, el comportamiento no está definido . [énfasis mío]

En este caso, tienes suerte porque descubriste que hiciste algo mal instantáneamente.

PD: esta es una explicación ondulada a mano