Stroustrup hizo algunos buenos comentarios al respecto en la conferencia Going Native 2013.
Simplemente pase a unos 25m50s en este video . (Recomiendo ver el video completo en realidad, pero esto salta a las cosas sobre la recolección de basura).
Cuando tiene un lenguaje realmente excelente que hace que sea fácil (y seguro, predecible, fácil de leer y fácil de enseñar) manejar objetos y valores de forma directa, evitando el uso (explícito) del montón, entonces ni siquiera quieres la recolección de basura.
Con C ++ moderno, y las cosas que tenemos en C ++ 11, la recolección de basura ya no es deseable, excepto en circunstancias limitadas. De hecho, incluso si un buen recolector de basura está integrado en uno de los principales compiladores de C ++, creo que no se usará con mucha frecuencia. Será más fácil , no más difícil, evitar el GC.
Él muestra este ejemplo:
void f(int n, int x) {
Gadget *p = new Gadget{n};
if(x<100) throw SomeException{};
if(x<200) return;
delete p;
}
Esto no es seguro en C ++. ¡Pero tampoco es seguro en Java! En C ++, si la función regresa temprano, delete
nunca se llamará. Pero si tuvo una recolección de basura completa, como en Java, simplemente recibe una sugerencia de que el objeto se destruirá "en algún momento en el futuro" ( Actualización: es aún peor que esto. Java nopromete llamar al finalizador alguna vez, tal vez nunca se llame). Esto no es lo suficientemente bueno si Gadget tiene un identificador de archivo abierto, o una conexión a una base de datos, o datos que ha guardado para escribir en una base de datos en un momento posterior. Queremos que el Gadget se destruya tan pronto como esté terminado, para liberar estos recursos lo antes posible. No desea que su servidor de bases de datos tenga problemas con miles de conexiones de bases de datos que ya no se necesitan, no sabe que su programa ha terminado de funcionar.
Entonces, ¿cuál es la solución? Hay algunos enfoques. El enfoque obvio, que utilizará para la gran mayoría de sus objetos es:
void f(int n, int x) {
Gadget p = {n}; // Just leave it on the stack (where it belongs!)
if(x<100) throw SomeException{};
if(x<200) return;
}
Esto requiere menos caracteres para escribir. No tiene que new
interponerse en el camino. No requiere que escriba Gadget
dos veces. El objeto se destruye al final de la función. Si esto es lo que quieres, esto es muy intuitivo. Gadget
s se comportan igual que int
o double
. Predecible, fácil de leer, fácil de enseñar. Todo es un "valor". A veces es un gran valor, pero los valores son más fáciles de enseñar porque no tienes esta cosa de 'acción a distancia' que obtienes con punteros (o referencias).
La mayoría de los objetos que crea son para usar solo en la función que los creó, y tal vez pasen como entradas a las funciones secundarias. El programador no debería tener que pensar en la "administración de memoria" al devolver objetos, o de otra manera compartir objetos en partes muy separadas del software.
El alcance y la vida útil son importantes. La mayoría de las veces, es más fácil si la vida útil es la misma que el alcance. Es más fácil de entender y más fácil de enseñar. Cuando desee una vida útil diferente, debería ser obvio leer el código que está haciendo esto, por shared_ptr
ejemplo , utilizando . (O devolviendo objetos (grandes) por valor, aprovechando la semántica de movimiento o unique_ptr
.
Esto puede parecer un problema de eficiencia. ¿Qué sucede si quiero devolver un gadget foo()
? La semántica de movimiento de C ++ 11 facilita la devolución de objetos grandes. Simplemente escriba Gadget foo() { ... }
y simplemente funcionará, y funcionará rápidamente. No necesita meterse consigo &&
mismo, simplemente devuelva las cosas por valor y el lenguaje a menudo podrá hacer las optimizaciones necesarias. (Incluso antes de C ++ 03, los compiladores hicieron un trabajo notablemente bueno al evitar copias innecesarias).
Como dijo Stroustrup en otra parte del video (parafraseando): "Solo un informático insistiría en copiar un objeto y luego destruir el original. (La audiencia se ríe). ¿Por qué no mover el objeto directamente a la nueva ubicación? Esto es lo que los humanos (no los informáticos) esperan ".
Cuando puede garantizar que solo se necesita una copia de un objeto, es mucho más fácil comprender la vida útil del objeto. Puede elegir qué política de por vida desea, y la recolección de basura está ahí si lo desea. Pero cuando comprenda los beneficios de los otros enfoques, encontrará que la recolección de basura se encuentra al final de su lista de preferencias.
Si eso no funciona para usted, usted puede utilizar unique_ptr
, o en su defecto, shared_ptr
. Bien escrito C ++ 11 es más corto, más fácil de leer y más fácil de enseñar que muchos otros lenguajes cuando se trata de la gestión de la memoria.