Eine Basisklasse für die Ausnahmebehandlung

8

Die Aufgabe von GotW # 8 besteht darin, eine ausnahmeutrale generische Stack-Datenstruktur in C ++ zu implementieren Nur der Destruktor des Template-Arguments wirft nicht. Der Trick besteht darin, potentiell auftretende Template-Argument-Operationen (Konstruktor, Kopierkonstruktor, Zuweisung) so zu behandeln, dass der Stack in einem konsistenten Zustand bleibt, wenn sie geworfen werden.

In der Lösung sagt Herb Sutter

  

Um diese Lösung einfacher zu halten, habe ich mich entschieden, die Basisklasse-Technik für ausnahmesicheres Ressourceneigentum nicht zu demonstrieren.

Nachdem ich gegoogelt hatte, fand ich diese Antwort von Dave Abrahams stammt aus dem Jahr 1997. In seiner Lösung behandelt er die Zuordnung und Löschung des Speichers in der Basisklasse und implementiert die Stapeloperationen in der Unterklasse. Auf diese Weise stellt er sicher, dass das Kopieren von Elementen im Kopierkonstruktor von der Speicherzuweisung getrennt ist. Wenn das Kopieren fehlschlägt, wird der Basisklassendestruktor aufgerufen, egal was passiert.

Als Referenz, hier ist Daves Kopierkonstruktor mit meinem Kommentar hinzugefügt:

%Vor%

Wenn der Basiskonstruktor erfolgreich ist, ist die Speicherbereinigung im Basisdestruktor garantiert, selbst wenn der Kopierkonstruktor der Unterklasse auslöst.

Meine Fragen sind:

  1. Gibt es einen anderen Nutzen für den Ansatz, außer wie oben beschrieben?
  2. Ich habe diesen Kopierkonstruktor entwickelt, als ich das Problem selbst gelöst habe:

    %Vor%

    Ich finde es etwas umständlich, eine Basisklasse zu haben, wenn man mit diesem Ansatz vergleicht. Gibt es einen Grund, warum die Basisklassentechnik gegenüber dieser temp-copy-then-swap-Methode bevorzugt werden sollte? Beachten Sie, dass sowohl Dave als auch ich das swap() Mitglied haben, weil wir es in unserem operator=() verwenden.

  3. Dave Abrahams 'Technik scheint nicht sehr bekannt zu sein (laut Google). Hat es einen anderen Namen, ist es Standard, habe ich etwas verpasst?

Anmerkungen:

  • nehme an, dass Dave's Push() in einer Schleife meiner Verwendung von std::copy entspricht
  • Lassen Sie uns schlaue Zeiger aus der Antwort heraushalten, da ihre Verwendung den Aspekt der expliziten Speicherverwaltung in dieser Übung überflüssig machen würde
Irfy 26.03.2013, 18:10
quelle

1 Antwort

1

Im Verhalten sind die beiden Implementierungen gleich. Sie richten beide ein verwaltetes Speicherzuordnungsobjekt ein, das beim Beenden des Bereichs bereinigt wird, wenn der Konstruktor fehlschlägt. Das Kopieren auf eine temporäre Variable könnte teurer sein, aber, wie in den Kommentaren erwähnt, würde std::move wahrscheinlich diese zusätzlichen Kosten zunichte machen. Als Antwort auf Ihre spezifischen Fragen:

  1. Das Beispiel von Abraham verschiebt die Heap-Zuweisung weiter von Ihren tatsächlichen Klassenimplementierungsdetails entfernt. Wenn Sie vor und nach dem Kopieren Ihres Arrays eine komplexere Speicherbearbeitung durchführen, kann es in Ihrem Code etwas schwieriger sein, die korrekte Verwaltung aller Entitäten sicherzustellen. Ansonsten sehe ich keine expliziten Details, die Sie in Bezug auf das Verhalten der ersten Implementierung nicht bereits über den Stil hinaus abgedeckt haben.
  2. Abrahams Implementierung abstrahiert die Aufräumarbeiten an einem einzigen Ort. Wenn mehrere Klassen StackBase<T> verwenden, können sie sicher annehmen, dass ihr dynamischer Speicher bereinigt wird, wenn sie eine Ausnahme auslösen. In Ihrer Implementierung müssten Sie das temporäre Objekt und den Auslagerungscode (zumindest Teile davon) neu schreiben, um dasselbe zu erreichen. Effektiv verringert diese Implementierung die Anzahl von Zeilen, um mehrere Unterklassen von StackBase zu implementieren. Bei der Implementierung wird jedoch die mehrfache Vererbung vermieden, wenn Sie eine zusätzliche Speicherzuweisung auf einer anderen Basisklasse wünschen. Ihr Code vermeidet auch die Zeit und die Größen für das Blähieren von Template-Code-Blossungen - obwohl ich dies in den meisten Fällen nicht für sehr negativ halte. Ich würde wahrscheinlich etwas verwenden, das Ihrem Code sehr nahe kommt, es sei denn, ich habe versucht, einen sehr allgemeinen Anwendungsfallcode zu schreiben.
  3. Ich weiß nicht, ob dieser Ansatz einen bestimmten Namen hat - ich werde ihn aktualisieren, wenn ich einen finde - aber ich habe gesehen, dass er in mindestens einem C ++ Programmierbuch verwendet wurde.
Pyrce 26.03.2013, 19:30
quelle

Tags und Links