Tout d'abord, je sais très bien pourquoi il n'y a pas de construction «enfin» en C ++? mais une discussion de plus en plus longue sur une autre question semble justifier une question distincte.
Mis à part le problème qu'en finally
C # et Java ne peuvent essentiellement exister qu'une seule fois (== 1) par portée et qu'une seule portée peut avoir plusieurs (== n) destructeurs C ++, je pense qu'ils sont essentiellement la même chose. (Avec quelques différences techniques.)
Cependant, un autre utilisateur a fait valoir :
... J'essayais de dire qu'un dtor est intrinsèquement un outil pour (Release sematics) et finalement est intrinsèquement un outil pour (Commit semantics). Si vous ne voyez pas pourquoi: réfléchissez à la raison pour laquelle il est légitime de lancer des exceptions les unes sur les autres dans des blocs enfin, et pourquoi il n'en va pas de même pour les destructeurs. (Dans un certain sens, c'est une chose entre données et contrôle. Les destructeurs sont pour libérer des données, enfin pour libérer le contrôle. Ils sont différents; il est malheureux que C ++ les lie ensemble.)
Quelqu'un peut-il clarifier cela?
la source
A
etB
. Si un thread est lancé, l'annulation de laA's
transaction ne doit pas détruire les ressources allouées dansB
, par exemple - les états du thread sont indépendants les uns des autres et la mémoire persistante vivant sur le tas est indépendante des deux. Cependant, généralement en C ++, la mémoire de tas est toujours liée aux objets de la pile.std::vector
objet peut vivre sur la pile mais pointer vers la mémoire sur le tas - à la fois l'objet vectoriel (sur la pile) et son contenu (sur le tas) seraient désalloués lors d'un déroulement de pile dans ce cas, car la destruction du vecteur sur la pile invoquerait un destructeur qui libère la mémoire associée sur le tas (et détruirait également ces éléments de tas). En règle générale, pour des raisons de sécurité d'exception, la plupart des objets C ++ vivent sur la pile, même s'ils ne gèrent que la mémoire pointant sur le tas, automatisant le processus de libération du tas et de la mémoire de la pile lors du déroulement de la pile.Heureux que vous ayez posté cette question. :)
J'essayais de dire que les destructeurs et
finally
sont conceptuellement différents:finally
est pour retourner à l'appelant ( contrôle )Considérons, disons, ce pseudo-code hypothétique:
finally
ici résout entièrement un problème de contrôle et non un problème de gestion des ressources.Cela n'aurait aucun sens de le faire dans un destructeur pour diverses raisons:
logfile.print
d'échouer, alors que la destruction (conceptuellement) ne peut pas échouerVoici un autre exemple, cette fois comme en Javascript:
Dans l'exemple ci-dessus, encore une fois, il n'y a aucune ressource à libérer.
En fait, le
finally
bloc acquiert des ressources en interne pour atteindre son objectif, ce qui pourrait potentiellement échouer. Par conséquent, il n'est pas logique d'utiliser un destructeur (si Javascript en avait un).D'un autre côté, dans cet exemple:
finally
est la destruction d' une ressource,b
. C'est un problème de données. Le problème n'est pas de retourner proprement le contrôle à l'appelant, mais plutôt d'éviter les fuites de ressources.L'échec n'est pas une option et ne devrait (conceptuellement) jamais se produire.
Chaque version de
b
est nécessairement associée à une acquisition, et il est logique d'utiliser RAII.En d'autres termes, simplement parce que vous pouvez utiliser soit pour simuler soit cela ne signifie pas que les deux sont un seul et même problème ou que les deux sont des solutions appropriées pour les deux problèmes.
la source
finally
est principalement utilisé pour libérer des ressources (autres que la mémoire) y tient -il compte?finally
.finally
clause. La vision du monde C ++ introduirait une classe qui gère cette «ressource» d'une affectation à une variable pseudo-globale. Quel sens conceptuel cela fait-il? Mais les destructeurs sont le marteau de C ++ pour l'exécution de code de fin de bloc requise.La réponse de k3b l'exprime vraiment bien:
Quant aux «ressources», j'aime me référer à Jon Kalb: RAII devrait signifier que l'acquisition de responsabilité est l'initialisation .
Quoi qu'il en soit, comme pour implicite vs explicite, cela semble vraiment être le cas:
Je pense que c'est tout pour la partie conceptuelle, ...
... maintenant il y a à mon humble avis des détails intéressants:
fault
bloc pour exécuter du code qui ne devrait s'exécuter qu'en cas de sortie de portée exceptionnelle.SCOPE_EXIT
,SCOPE_FAIL
etSCOPE_SUCCESS
dans la bibliothèque de folie . Voir Andrei Alexandrescu: Gestion des erreurs dans C ++ / Flux de contrôle déclaratif (tenue au NDC 2014 )Je ne pense pas non plus que le c'tor / d'tor ait besoin conceptuellement d '"acquérir" ou de "créer" quoi que ce soit, à part la responsabilité d'exécuter du code dans le destructeur. C'est ce qui fait finalement aussi: exécuter du code.
Et bien que le code dans un bloc finalement puisse certainement lever une exception, ce n'est pas assez de distinction pour moi pour dire qu'ils sont conceptuellement différents au-dessus de l'explicite et de l'implicite.
(De plus, je ne suis pas du tout convaincu que le "bon" code devrait finalement disparaître - c'est peut-être une autre question en soi.)
la source
observer
exemple que lancer là-bas serait une très mauvaise idée.) N'hésitez pas à ouvrir un chat, si vous voulez en discuter plus avant. C'était certainement amusant de réfléchir à vos arguments. À votre santé.