c++ - pueden - Sobre el uso de nuevo y eliminar, y el consejo de Stroustrup
no me andan los hashtags en instagram (3)
Sobre el uso de nuevos y eliminar, y el consejo de Stroustrup ...
Dice algo como (pero no exactamente, esto es de mis notas de su libro):
Una regla de oro es que, lo
new
pertenece a los constructores y las operaciones similares, ladelete
pertenece a los destructores. Además, lonew
se usa a menudo en argumentos para los manejadores de recursos. De lo contrario, evite usarnew
ydelete
, use los identificadores de recursos (punteros inteligentes) en su lugar.
Me preguntaba si las personas más experimentadas con C ++ 11 realmente han aplicado esto o no.
Mi impresión de esto fue, wow esto parece ser una regla muy buena para seguir. Pero luego tuve sospechas, como para cualquier regla general. Al final del día, terminará usando new y delete cuando sea necesario. Pero tal vez esta regla es una buena pauta que no conozco.
Es una gran regla. De hecho, puede evitar el uso de new
argumentos en los punteros inteligentes utilizando las funciones apropiadas de make_
. Por ejemplo, en lugar de:
std::shared_ptr<int> p(new int(5));
A menudo se puede hacer:
auto p = std::make_shared<int>(5);
Esto también tiene el beneficio de ser más una excepción segura. Si bien aún no existe un std::make_unique
, se planea ingresar a C ++ 14 (ya se encuentra en el borrador de trabajo). Si lo quieres ahora, hay algunas implementaciones existentes .
Puede ir un paso más allá e incluso evitar usar new
y delete
en constructores y destructores. Si siempre envuelve objetos asignados dinámicamente en punteros inteligentes, incluso cuando son miembros de la clase, no necesitará administrar su propia memoria. Ver la Regla del Cero . La idea es que no es responsabilidad de su clase implementar ningún tipo de semántica de propiedad ( SRP ): para eso están los punteros inteligentes. Entonces, teóricamente, nunca tendrás que escribir constructores de copiar / mover, copiar / mover operadores de asignación o destructores, porque las funciones implícitamente definidas generalmente harán lo correcto.
La forma en que lo pienso es que cada recurso debe ser propiedad de algo. El propietario es el responsable de la limpieza. Por lo general, este propietario es un puntero inteligente de algún tipo, pero incluso std :: vector es un recurso propietario: el bloque de memoria que almacena sus elementos contiguos. Este consejo es válido no solo para la memoria, sino también para cualquier recurso, como descriptores de archivos, manejadores de bases de datos, exclusión mutua, etc.
Cuando llama a new y delete manualmente en alguna parte de su código que no es una clase contenedora, el programador se convierte en el propietario del recurso. Con la propiedad viene la responsabilidad de limpiar después de ti mismo. Ahora usted y todos los programadores de mantenimiento que vienen después deben asegurarse de que todas las rutas de código después de la nueva conduzcan finalmente a una eliminación. Incluso para funciones simples es muy fácil equivocarse. Con excepciones, es casi imposible, a menos que cuidadosamente ajuste todo en los bloques de captura de prueba, las penalizaciones resultantes en el rendimiento del tiempo de ejecución y contamine su código con ámbitos adicionales y una lógica de excepción innecesaria. Finalmente, incluso si lo hace bien, simplemente perdió su tiempo haciendo este tedioso trabajo de administración de recursos. El compilador es una herramienta que puede hacer este trabajo por usted, úselo.
La peor situación es cuando algún subsistema asigna un recurso, se pasa por la aplicación y otro subsistema lejano lo libera. El número de rutas de código posibles en esta situación es intratable. Es muy difícil, si no imposible, para un ser humano razonar y confiar. En mi opinión, este estilo de programación es inalcanzable. ¿Cuántos proyectos C ha trabajado en el pasado que están plagados de errores de memoria, especialmente en rutas de manejo de errores raramente si nunca se han ejecutado? He tratado con más de lo que me gustaría ver más.
C tiene administración de memoria manual, Java y otros tienen recolección de basura. C ++ tiene RAII. Es tan eficiente como C y casi tan seguro como la recolección de basura.
Mi regla es simple: si te encuentras limpiando manualmente algún recurso, acabas de escribir un error.
Parece más una encuesta que una pregunta, pero aquí va: en el código de la aplicación generalmente no uso nada new
. Debido a nuestras directrices de codificación, el código utiliza un puntero, pero ninguno de estos punteros "desnudos" está transfiriendo la propiedad. Todos los objetos son propiedad de algún otro objeto.
Para ser justos, cuando los objetos deben asignarse, la asignación generalmente utiliza algo moralmente equivalente a std::make_shared<T>(...)
que a veces aparece en el código de la aplicación. Una razón importante para esta ausencia más bien completa de new
(o similares) es que los objetos se asignan generalmente usando asignadores con estado y no hacerlo a través de un administrador de recursos realmente resulta ser bastante complicado. Por lo tanto, hay poco lugar para la asignación directa de memoria utilizando una versión new
o una ubicación de la misma en el código de la aplicación.
En algunos códigos de infraestructura, especialmente cuando se crean contenedores personalizados, la situación es ligeramente diferente: hay memoria asignada (desde los asignadores y se inicializa usando la ubicación new
). Sin embargo, incluso allí, cualquier resultado de la asignación de memoria y la inicialización de objetos se pasa inmediatamente a los administradores de recursos. Básicamente, no puedo lidiar con la administración explícita de recursos y el uso de administradores de recursos me alivia del trabajo necesario.