Punteros y memoria

Direcciones, punteros, la pila y el heap, new y delete, y cazar fugas: la memoria de C++ dibujada en vivo.

14 aulas · 11 horas de práctica · en el navegador, sin instalar nada

Temario

  1. La memoria como casilleros — Cada variable vive en un casillero con número: su dirección. & te la dice, sizeof cuenta cuántos casilleros ocupa, y un arreglo son casilleros seguidos.
  2. Punteros: cruzar la flecha — Un puntero es una variable que guarda una dirección. Con * se cruza la flecha para leer o cambiar lo apuntado, y la flecha se puede mover a otro lado.
  3. nullptr: la puerta que no lleva a ningún lado — Un puntero puede no apuntar a nada: nullptr. Cruzarlo rompe el programa, así que se revisa antes. Y una función puede devolver nullptr para decir "no encontré".
  4. Punteros y arreglos: la flecha que recorre — El nombre de un arreglo es la dirección de su primer elemento. p + 1 es el elemento siguiente, p++ mueve la flecha, y restando punteros sabés cuántos casilleros hay entre ellos.
  5. Referencias y punteros — Una referencia es otro nombre para la misma variable: no tiene casillero propio, no se mueve y nunca es nula. Un puntero es una variable aparte que guarda una dirección. Cuándo conviene cada uno.
  6. El control remoto: punteros a funciones — Una función recibe copias. Si le pasás una dirección, puede cambiar la variable de quien la llamó: el control remoto apunta al robot. Y un arreglo que se pasa a una función llega como puntero.
  7. La pila y el heap — Las variables locales viven en la pila y se mueren cuando termina su función. Lo que pedís con new vive en el heap hasta que lo devolvés con delete. Las dos estanterías del depósito.
  8. new y delete: la fábrica en el heap — new también fabrica objetos: un robot entero en el heap, que se maneja por la flecha con ->. Cada new tiene su delete, y copiar un puntero no fabrica otro robot.
  9. Fugas: las cajas huérfanas — Una fuga es una caja del heap que nadie devolvió. Las tres formas clásicas de perder una: el olvido, la flecha pisada y la salida temprana. Y la regla que las evita: cada caja tiene un dueño.
  10. Punteros colgando y doble delete — Después del delete, el puntero sigue apuntando al hueco: cuelga. Leerlo da basura, devolverlo otra vez es un doble delete. nullptr es el seguro, y una función que libera tiene que poder tocar el puntero de afuera.
  11. Arreglos dinámicos: new[] y delete[] — Un arreglo del tamaño que haga falta, decidido mientras el programa corre: new[] lo pide, delete[] lo devuelve. Y para agrandarlo, se pide uno nuevo, se copia y se devuelve el viejo: lo que hace un vector por dentro.
  12. Los compartimentos del submarino — Un submarino que respira de un arreglo de tanques en el heap: un puntero recorre los tanques, otro marca el final, y los compartimentos inundados son nullptr. Todo el módulo en una inmersión.
  13. const con punteros: lo que no se toca — const int* promete no tocar lo apuntado; int* const, no mover la flecha. Se leen de derecha a izquierda, y en los parámetros son una promesa que el compilador hace cumplir.
  14. Cazá el leak — Construí a mano lo que el depósito hace por dentro: un registro de cada caja del heap y de quién la pidió. Con eso, las funciones que pierden memoria se delatan solas. Después, se arreglan.

Es parte de