Memoria y recolector de basura en C++: por qué su código no perdona errores
\n\nCuando un desarrollador pasa a C++ después de Python, Java o C#, a menudo recibe una ducha fría. Donde antes podía simplemente crear un objeto y olvidarse de él (¡gracias al recolector de basura!), en C++ hay que pensar en cada byte. Y esto no es un error, es una característica. C++ no perdona la pereza, pero a cambio ofrece un control absoluto sobre la memoria y, en consecuencia, sobre el rendimiento.
\n\nEn este artículo analizaremos por qué C++ no tiene un recolector de basura (GC) incorporado, cómo funciona la gestión manual de memoria y qué herramientas modernas (RAII, punteros inteligentes) permiten escribir código seguro y rápido sin dolores de cabeza. Si programa en C++ o está empezando, este material es para usted.
\n\nMito n.º 1: C++ tiene un recolector de basura
\n\nDespejemos de inmediato el principal malentendido. En C++ estándar (ISO C++98/11/14/17/20/23) no hay un recolector de basura incorporado. Sí, puede conectar una biblioteca externa (por ejemplo, libgc de Hans Boehm), pero eso será un parche, no un mecanismo nativo. ¿Por qué?
- \n
- Filosofía de C++: «No pagas por lo que no usas». El recolector de basura consume recursos (CPU, memoria) e introduce pausas no deterministas. Para sistemas en tiempo real, juegos, sistemas embebidos, esto es letal. \n
- Determinismo: En C++ usted sabe exactamente cuándo se destruirá un objeto. En GC, no (solo «en algún momento»). \n
- RAII (Resource Acquisition Is Initialization) es nuestro «recolector de basura», pero manual y predecible. \n
Cómo funciona la gestión manual de memoria en C++
\n\nLo clásico: new y delete. Asignó memoria en el heap, no olvide liberarla.
#include <iostream>\n\nint main() {\n int* p = new int(42); // asignamos memoria para un int\n std::cout << *p << std::endl;\n delete p; // liberamos — de lo contrario, fuga\n return 0;\n}\n\n¿Parece sencillo? Ahora imagine que entre new y delete puede ocurrir una excepción, un return, o alguien olvida llamar a delete. Obtenemos la clásica fuga de memoria en C++. Y esto es solo el comienzo: doble eliminación (double delete), punteros colgantes (dangling pointers) — ahí es donde está el verdadero infierno.
RAII: el mejor amigo del desarrollador de C++
\n\nRAII no es solo una abreviatura, es una forma de vida en C++. La idea: el recurso (memoria, archivo, mutex) se adquiere en el constructor y se libera en el destructor. Tan pronto como el objeto sale del ámbito, el destructor se llama automáticamente. De forma garantizada.
\n\nEjemplo con el puntero inteligente std::unique_ptr:
#include <memory>\n#include <iostream>\n\nclass MyClass {\npublic:\n MyClass() { std::cout << "Creado\\n"; }\n ~MyClass() { std::cout << "Destruido\\n"; }\n};\n\nint main() {\n std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>();\n // ¡Ningún delete! La memoria se liberará automáticamente al salir del bloque\n return 0;\n}\n\nSalida: Creado, luego Destruido. Sin fugas, sin llamadas manuales. RAII reemplaza al recolector de basura en C++, pero lo hace de forma predecible y sin pausas.
Punteros inteligentes: unique_ptr, shared_ptr, weak_ptr
\n\nSi todavía usa new/delete sin envoltorio, deténgase. El C++ moderno (a partir de C++11) ofrece punteros inteligentes que automatizan la gestión de memoria.
std::unique_ptr
\nPropiedad exclusiva. No se puede copiar, solo mover. Ideal para la propiedad única de un recurso.
\n\nstd::unique_ptr<int> p1 = std::make_unique<int>(10);\n// std::unique_ptr<int> p2 = p1; // ¡Error! Copia prohibida\nstd::unique_ptr<int> p2 = std::move(p1); // Ok, transferencia de propiedad\n\n