Primero, soy muy consciente de ¿Por qué no hay una construcción 'finalmente' en C ++? pero una discusión de comentarios de larga duración sobre otra pregunta parece justificar una pregunta separada.
Además del problema de que finally
en C # y Java básicamente pueden existir solo una vez (== 1) por alcance y un solo alcance puede tener múltiples (== n) destructores de C ++, creo que son esencialmente lo mismo. (Con algunas diferencias técnicas).
Sin embargo, otro usuario argumentó :
... Estaba tratando de decir que un dtor es inherentemente una herramienta para (Release sematics) y finalmente es inherentemente una herramienta para (Commit semantics). Si no ve por qué: considere por qué es legítimo lanzar excepciones una encima de la otra en bloques finalmente, y por qué lo mismo no es para destructores. (En cierto sentido, es una cuestión de datos versus control. Los destructores son para liberar datos, finalmente son para liberar control. Son diferentes; es lamentable que C ++ los una).
Alguien puede aclarar esto?
fuente
A
yB
. Si se arroja un subproceso, laA's
transacción de reversión no debe destruir los recursos asignadosB
, por ejemplo, los estados del subproceso son independientes entre sí, y la memoria persistente que vive en el montón es independiente de ambos. Sin embargo, normalmente en C ++, la memoria de almacenamiento dinámico todavía está vinculada a los objetos en la pila.std::vector
objeto podría vivir en la pila pero apuntar a la memoria en el montón: tanto el objeto vectorial (en la pila) como su contenido (en el montón) se desasignarían durante una desconexión de la pila en ese caso, ya que destruir el vector en la pila invocaría un destructor que libera la memoria asociada en el montón (y también destruiría esos elementos del montón). Por lo general, para la seguridad de la excepción, la mayoría de los objetos C ++ viven en la pila, incluso si son solo identificadores que apuntan a la memoria en el montón, automatizando el proceso de liberar tanto el almacenamiento dinámico como la memoria de pila en la pila.Me alegra que hayas publicado esto como una pregunta. :)
Estaba tratando de decir que los destructores y
finally
conceptualmente son diferentes:finally
es para volver a la persona que llama ( control )Considere, digamos, este pseudocódigo hipotético:
finally
aquí está resolviendo completamente un problema de control y no un problema de gestión de recursos.No tendría sentido hacer eso en un destructor por una variedad de razones:
logfile.print
fracasar, mientras que la destrucción (conceptual) no puede fallarAquí hay otro ejemplo, esta vez como en Javascript:
En el ejemplo anterior, nuevamente, no hay recursos para liberar.
De hecho, el
finally
bloque está adquiriendo recursos internamente para lograr su objetivo, lo que podría fallar. Por lo tanto, no tiene sentido usar un destructor (si Javascript tenía uno).Por otro lado, en este ejemplo:
finally
está destruyendo un recurso,b
. Es un problema de datos. El problema no se trata de devolver limpiamente el control a la persona que llama, sino de evitar pérdidas de recursos.El fracaso no es una opción, y nunca (conceptualmente) debería ocurrir.
Cada lanzamiento de
b
necesariamente está emparejado con una adquisición, y tiene sentido usar RAII.En otras palabras, solo porque puede usar cualquiera para simular eso no significa que ambos son el mismo problema o que ambos son soluciones apropiadas para ambos problemas.
fuente
finally
se usa principalmente para liberar recursos (sin memoria)?finally
.finally
cláusula. La cosmovisión de C ++ introduciría una clase que administra este "recurso" de una asignación a una variable pseudo-global. ¿Qué sentido conceptual tiene eso? Pero los destructores son el martillo de C ++ para la ejecución requerida del código de fin de bloque.La respuesta de k3b realmente lo expresa muy bien:
En cuanto a "recursos", me gusta referirme a Jon Kalb: RAII debería significar Adquisición de responsabilidad es inicialización .
De todos modos, en cuanto a lo implícito frente a lo explícito, esto parece ser realmente:
Creo que eso es todo por la parte conceptual, ...
... ahora hay en mi humilde opinión algunos detalles interesantes:
fault
bloque para ejecutar código que solo debería ejecutarse en caso de una salida de alcance excepcional.SCOPE_EXIT
,SCOPE_FAIL
ySCOPE_SUCCESS
en la biblioteca de locura . Ver Andrei Alexandrescu: Manejo de errores en C ++ / Flujo de control declarativo (celebrado en NDC 2014 )Tampoco creo que c'tor / d'tor necesite conceptualmente "adquirir" o "crear" nada, aparte de la responsabilidad de ejecutar algún código en el destructor. Que es lo que finalmente hace también: ejecuta un código.
Y aunque el código en un bloque finalmente puede arrojar una excepción, no es suficiente distinción para mí para decir que son conceptualmente diferentes por encima de lo explícito frente a lo implícito.
(Además, no estoy convencido de que ese código "bueno" deba arrojarse finalmente, tal vez esa sea otra pregunta completa para sí mismo).
fuente
observer
ejemplo que lanzar allí sería una muy mala idea). Siéntase libre de abrir un chat, si desea discutir esto más a fondo. Ciertamente fue divertido pensar en tus argumentos. Salud.