Smart pointers
Quién libera cada caja: unique_ptr, make_unique y mover, shared_ptr y su contador, weak_ptr para romper ciclos, observadores, deleters propios y un árbol de escena sin un solo delete.
12 aulas · 10 horas de práctica · en el navegador, sin instalar nada
Temario
- Ownership: ¿quién libera? — Cada caja del heap tiene un dueño: el que la devuelve. Los demás punteros a la misma caja solo miran. Quién es el dueño en cada caso (el que recibe, la función que se la queda, un objeto), y una clase que hace de dueño sola.
- unique_ptr — El dueño del aula anterior, ya hecho: unique_ptr guarda una caja y la devuelve cuando muere. Se usa como un puntero, avisa en el tipo que es el dueño, no se puede copiar, y con reset() suelta la caja antes de tiempo.
- make_unique y mover un unique_ptr — make_unique arma la caja y el dueño en un solo paso, sin un new a la vista. Y como un unique_ptr no se copia, se mueve: std::move le pasa la caja a otro, y el de antes queda vacío. Una línea de montaje donde cada robot pasa de mano en mano.
- unique_ptr en contenedores con polimorfismo — La flota de barcos distintos del módulo de herencia, ahora sin un solo delete: un vector<unique_ptr<Barco>> es dueño de cada barco. Recorrerlo sin copiar, pasarlo a una función, sacar un barco (que se devuelve solo) y por qué el destructor virtual sigue haciendo falta.
- shared_ptr y el contador de referencias — Cuando una caja tiene varios dueños de verdad, ninguno puede devolverla solo. shared_ptr se copia, y cada copia suma uno a un contador; la caja se devuelve cuando se va el último. El contador, dibujado en la caja.
- weak_ptr y los ciclos — Dos shared_ptr que se apuntan entre sí se mantienen vivos para siempre: el ciclo que nunca muere. weak_ptr mira sin ser dueño, así que no cuenta; para usar lo que mira, lock() pregunta si sigue vivo.
- Punteros crudos como observadores — Con los dueños en smart pointers, un puntero crudo pasa a querer decir una sola cosa: "miro, no soy dueño". Observadores con get(), una cola de aterrizaje que no es dueña de ningún avión, y el peligro de siempre: un observador que mira algo que ya se devolvió.
- Deleters propios — Un smart pointer no tiene por qué hacer delete: se le puede decir qué hacer con la caja cuando muere. Un deleter cierra una puerta, suelta un candado o llama a la función de limpieza de una biblioteca de C, salga por donde salga.
- Un árbol de escena con unique_ptr — Los motores de juegos guardan el mundo como un árbol: cada nodo es dueño de sus hijos y su posición es relativa al padre. Con unique_ptr, el árbol entero se devuelve solo, podar una rama es un erase y mudarla es un std::move.
- Cuándo usar cada uno — Una sola pregunta decide el tipo: ¿quién es dueño de esto? Uno solo: unique_ptr. Varios de verdad: shared_ptr. Nadie, solo mira: un puntero crudo o una referencia, o weak_ptr si lo mirado puede morir. Cinco casos de un juego, y quién sigue en pie cuando termina el nivel.
- Taller: entidades de un juego sin un solo leak — Un juego de naves donde todo lo que se mueve (balas, rocas, chispas) vive en un vector<unique_ptr<Entidad>>. Disparar, limpiar lo que murió, chocar, hacer nacer cosas mientras se recorre el mundo y reiniciar la partida, con un contador que muestra en vivo si algo se pierde.
- Taller: caché de texturas con shared_ptr y weak_ptr — Leer una imagen del disco es caro: si dos sprites usan el pasto, que se lea una vez. Una caché de weak_ptr mira las texturas sin mantenerlas vivas: los sprites son los dueños, y lo que nadie usa se devuelve solo.