Frage

Ich bin rübergekommen Dieser Artikel vor vielen Jahren von Andrei Alexandrescu und Petru Marginean geschrieben, in dem eine Dienstprogrammklasse namens ScopeGuard zum Schreiben von ausnahmesicherem Code vorgestellt und diskutiert wird.Ich würde gerne wissen, ob das Codieren mit diesen Objekten wirklich zu besserem Code führt oder ob es die Fehlerbehandlung verschleiert, indem der Rückruf des Wächters vielleicht besser in einem Catch-Block dargestellt würde?Hat jemand Erfahrung mit der Verwendung dieser im tatsächlichen Produktionscode?

War es hilfreich?

Lösung

Es verbessert definitiv Ihren Code.Ihre vorläufig formulierte Behauptung, dass es unklar sei und dass der Code eines verdienen würde catch block ist in C++ einfach nicht wahr, da RAII eine etablierte Redewendung ist.Ressourcenhandhabung in C++ Ist Dies erfolgt durch Ressourcenbeschaffung und die Speicherbereinigung erfolgt durch implizite Destruktoraufrufe.

Andererseits explizit catch Blöcke würden den Code aufblähen und zu subtilen Fehlern führen, da der Codefluss viel komplexer wird und die Ressourcenverwaltung explizit erfolgen muss.

RAII (einschließlich ScopeGuards) ist keine obskure Technik in C++, sondern eine fest etablierte Best Practice.

Andere Tipps

Ja.

Wenn es einen einzigen Teil des C++-Codes gibt, den ich jedem C++-Programmierer empfehlen kann, 10 Minuten damit zu verbringen, ihn zu lernen, dann ist es ScopeGuard (jetzt Teil der frei verfügbaren Version). Loki-Bibliothek).

Ich beschloss, eine (leicht modifizierte) Version von ScopeGuard für ein kleineres Win32-GUI-Programm zu verwenden, an dem ich arbeitete.Wie Sie vielleicht wissen, verfügt Win32 über viele verschiedene Arten von Ressourcen, die auf unterschiedliche Weise geschlossen werden müssen (z. B.Kernel-Handles werden normalerweise mit geschlossen CloseHandle(), GDI BeginPaint() muss mit gepaart werden EndPaint(), usw.) Ich habe ScopeGuard mit all diesen Ressourcen und auch zum Zuweisen von Arbeitspuffern verwendet new (z.B.für Zeichensatzkonvertierungen in/von Unicode).

Was mich erstaunte, war, wie viel kürzer Das Programm war. Im Grunde ist es eine Win-Win-Situation:Ihr Code wird gleichzeitig kürzer und robuster.Zukünftige Codeänderungen kann nichts auslaufen lassen.Sie können es einfach nicht.Wie cool ist das?

Ich verwende es oft, um die Speichernutzung zu schützen, also Dinge, die freigegeben werden müssen und vom Betriebssystem zurückgegeben wurden.Zum Beispiel:

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

Ich habe diese spezielle Vorlage nicht verwendet, aber ich habe schon einmal etwas Ähnliches verwendet.Ja, es führt zu klarerem Code im Vergleich zu ebenso robustem Code, der auf unterschiedliche Weise implementiert wird.

Ich denke, dass in den obigen Antworten ein wichtiger Hinweis fehlt.Wie andere bereits betont haben, können Sie Folgendes verwenden ScopeGuard um zugewiesene Ressourcen unabhängig von einem Fehler (Ausnahme) freizugeben.Aber das ist möglicherweise nicht das Einzige, wofür Sie Scope Guard verwenden möchten.Tatsächlich verwenden die Beispiele im verlinkten Artikel ScopeGuard für einen anderen Zweck:Transaktionen.Kurz gesagt: Es kann nützlich sein, wenn Sie mehrere Objekte haben (auch wenn diese Objekte RAII ordnungsgemäß verwenden), die Sie in einem Zustand halten müssen, der irgendwie korreliert ist.Wenn eine Zustandsänderung eines dieser Objekte zu einer Ausnahme führt (was meiner Meinung nach normalerweise bedeutet, dass sich der Zustand nicht geändert hat), müssen alle bereits vorgenommenen Änderungen rückgängig gemacht werden.Dadurch entstehen eigene Probleme (was passiert, wenn auch ein Rollback fehlschlägt?).Sie könnten versuchen, eine eigene Klasse einzuführen, die solche korrelierten Objekte verwaltet, aber wenn die Anzahl dieser Objekte zunimmt, würde es chaotisch werden und Sie würden wahrscheinlich auf die Verwendung zurückgreifen ScopeGuard intern sowieso.

Ja.

In C++ war es so wichtig, dass es in D sogar eine spezielle Syntax dafür gab:

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
}

Ich muss sagen: Nein, nein, das tut es nicht.Die Antworten hier helfen zu zeigen, warum es eine wirklich schreckliche Idee ist.Die Ressourcenverwaltung sollte über wiederverwendbare Klassen erfolgen.Das Einzige, was sie durch die Verwendung eines Bereichswächters erreicht haben, besteht darin, gegen DRY zu verstoßen und ihren ressourcenbefreienden Code in der gesamten Codebasis zu duplizieren, anstatt eine Klasse für die Verwaltung der Ressource zu schreiben, und das war’s dann für alles.

Wenn Scope Guards haben tatsächliche Verwendungszwecke, Ressourcenhandhabung jedoch nicht einer von ihnen.In diesem Fall sind sie dem einfachen RAII deutlich unterlegen, da RAII dedupliziert und automatisch ist und Scope Guards eine manuelle Codeduplizierung oder -überlastung darstellen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top