Question

Je suis tombé sur Cet article écrit par Andrei Alexandrescu et Petru Marginean il y a de nombreuses années, qui présente et discute d'une classe utilitaire appelée ScopeGuard pour écrire du code sécurisé contre les exceptions.J'aimerais savoir si le codage avec ces objets conduit vraiment à un meilleur code ou s'il obscurcit la gestion des erreurs, dans la mesure où peut-être le rappel du garde serait mieux présenté dans un bloc catch ?Quelqu'un a-t-il une expérience de leur utilisation dans le code de production réel ?

Était-ce utile?

La solution

Cela améliore définitivement votre code.Votre affirmation provisoirement formulée, selon laquelle c'est obscur et que ce code mériterait d'être catch block n'est tout simplement pas vrai en C++ car RAII est un idiome établi.Gestion des ressources en C++ est effectué par l'acquisition de ressources et le garbage collection se fait par des appels implicites de destructeur.

En revanche, explicite catch les blocs gonfleraient le code et introduiraient des erreurs subtiles car le flux de code devient beaucoup plus complexe et la gestion des ressources doit être effectuée explicitement.

RAII (y compris ScopeGuards) n'est pas une technique obscure en C++ mais une bonne pratique fermement établie.

Autres conseils

Oui.

S'il existe un seul morceau de code C++ que je pourrais recommander à chaque programmeur C++ de consacrer 10 minutes à apprendre, c'est bien ScopeGuard (qui fait désormais partie du programme disponible gratuitement). Bibliothèque Loki).

J'ai décidé d'essayer d'utiliser une version (légèrement modifiée) de ScopeGuard pour un petit programme GUI Win32 sur lequel je travaillais.Win32, comme vous le savez peut-être, possède de nombreux types de ressources qui doivent être fermées de différentes manières (par ex.les descripteurs du noyau sont généralement fermés par CloseHandle(), GDI BeginPaint() doit être associé à EndPaint(), etc.) J'ai utilisé ScopeGuard avec toutes ces ressources, et aussi pour allouer des tampons de travail avec new (par exemple.pour les conversions de jeux de caractères vers/depuis Unicode).

Ce qui m'a étonné, c'est à quel point plus court le programme était. En gros, c'est gagnant-gagnant :votre code devient à la fois plus court et plus robuste.Modifications futures du code je ne peux rien divulguer.Ils ne le peuvent tout simplement pas.À quel point cela est cool?

Je l'utilise souvent pour protéger l'utilisation de la mémoire, les éléments qui doivent être libérés et qui ont été renvoyés par le système d'exploitation.Par exemple:

DATA_BLOB blobIn, blobOut;
blobIn.pbData=const_cast<BYTE*>(data);
blobIn.cbData=length;

CryptUnprotectData(&blobIn, NULL, NULL, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN, &blobOut);
Guard guardBlob=guardFn(::LocalFree, blobOut.pbData);
// do stuff with blobOut.pbData

Je n'ai pas utilisé ce modèle particulier mais j'ai déjà utilisé quelque chose de similaire.Oui, cela conduit à un code plus clair par rapport à un code tout aussi robuste implémenté de différentes manières.

Je pense que les réponses ci-dessus manquent d'une note importante.Comme d'autres l'ont souligné, vous pouvez utiliser ScopeGuard afin de libérer les ressources allouées indépendamment d'une panne (exception).Mais ce n’est peut-être pas la seule chose pour laquelle vous souhaiterez peut-être utiliser Scope Guard.En fait, les exemples d'utilisation d'articles liés ScopeGuard dans un autre but :transcations.En bref, cela peut être utile si vous avez plusieurs objets (même si ces objets utilisent correctement RAII) que vous devez conserver dans un état corrélé d'une manière ou d'une autre.Si le changement d'état de l'un de ces objets entraîne une exception (ce qui, je suppose, signifie généralement que son état n'a pas changé), alors toutes les modifications déjà appliquées doivent être annulées.Cela crée son propre ensemble de problèmes (que se passe-t-il si une restauration échoue également ?).Vous pouvez essayer de déployer votre propre classe qui gère de tels objets corrélés, mais à mesure que le nombre de ces objets augmente, cela deviendrait compliqué et vous recommenceriez probablement à utiliser ScopeGuard en interne en tout cas.

Oui.

C'était si important en C++ qu'il y avait même une syntaxe spéciale pour cela en D :

void somefunction() {
    writeln("function enter");
    // c++ has similar constructs but not in syntax level
    scope(exit) writeln("function exit");

    // do what ever you do, you never miss the function exit output
}

Je dois dire que non, non, ce n'est pas le cas.Les réponses ici aident à démontrer pourquoi c'est une idée vraiment horrible.La gestion des ressources doit être effectuée via des classes réutilisables.La seule chose qu'ils ont réalisée en utilisant un scope guard est de violer DRY le wazoo et de dupliquer leur code de libération de ressources dans toute leur base de code, au lieu d'écrire une classe pour gérer la ressource et c'est tout, pour l'ensemble.

Si les gardes de portée ont des utilisations réelles, la gestion des ressources est pas l'un d'eux.Dans ce cas, ils sont massivement inférieurs au RAII simple, car le RAII est dédupliqué et automatique et les gardes de portée sont une duplication ou un effondrement manuel du code.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top