Je suis tombé sur cet article écrit par Andrei Alexandrescu et Petru Marginean il y a plusieurs années, qui présente et discute d'une classe utilitaire appelé ScopeGuard pour l'écriture du code garanti sans exception. Je voudrais savoir si le codage avec ces objets conduit vraiment à mieux de code ou si elle dissimule erreur de manipulation, que peut-être le gardien de la fonction de rappel devrait être mieux présenté dans un bloc catch? Quelqu'un aurait-il une expérience d'utilisation de ces à la production effective de code?
Réponses
Trop de publicités?Il améliore certainement votre code. Votre provisoirement formulé de réclamation, qu'il est obscur et que le code serait le mérite d'un catch
bloc est tout simplement pas vrai en C++ parce que RAII est un idiome. Ressources de manutention en C++ est fait par l'acquisition de ressources et de collecte des ordures se fait par implicite des appels de destructeur.
D'autre part, explicite catch
blocs serait gonfler le code et introduire subtile des erreurs parce que le flux de code devient beaucoup plus complexe et les ressources de manipulation doit être fait de manière explicite.
RAII (et particulièrement ScopeGuard
s) n'est pas un obscur technique en C++, mais fermement établi les meilleures pratiques.
Oui.
Si il y a un seul morceau de code C++ que je pourrais recommander à chaque programmeur C++ de passer 10 minutes à l'apprentissage, il est ScopeGuard (qui fait maintenant partie de l'librement disponible Loki bibliothèque).
J'ai décidé d'essayer à l'aide d'un (légèrement modifié) version de ScopeGuard pour un petit GUI Win32 programme je travaillais. Win32 comme vous le savez a beaucoup de différents types de ressources qui doivent être fermés de différentes façons (par exemple, le noyau poignées sont généralement fermés avec CloseHandle()
, GDI BeginPaint()
doit être couplé avec un EndPaint()
, etc.) J'ai utilisé ScopeGuard avec toutes ces ressources, et aussi pour l'allocation de travail tampons avec new
(par exemple, pour le jeu de caractères conversions/Unicode).
Ce qui m'a étonné comment beaucoup plus court que le programme a été. Fondamentalement, il est un gagnant-gagnant: votre code est plus court et plus robuste à la fois. Futures modifications du code ne peut pas de fuite rien. Ils ne peuvent tout simplement pas. C'est pas cool ça?
Je l'utilise souvent pour protéger l'utilisation de la mémoire, des choses qui doivent être libérées et qui ont été renvoyées 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