Abgeschlossenes Kapitel 3 Ausnahme- und Fehlerbehandlung, Auszug
Konstruktoren und Ausnahmen
Dieses Thema wird in der C++-Community oft erwähnt, aber in der Delphi-Community scheint sich niemand darum gekümmert zu haben. Vielleicht aufgrund der Eigenschaften der Sprache müssen sich Delphi-Programmierer über dieses Problem keine Sorgen machen. Aber ich denke, Delphi-Programmierer sollten dieses Problem auch verstehen und wissen, was die Sprache uns bietet, damit wir es so einfach ignorieren können. Wie das Sprichwort sagt: „Wenn Sie von Segnungen umgeben sind, müssen Sie die Segnungen kennen.“ Wir wissen, dass der Konstruktor einer Klasse keinen Rückgabewert hat. Wenn der Konstruktor das Objekt nicht erstellen kann, ist es unmöglich, sich auf die Rückgabe eines Fehlercodes zu verlassen. Wie kann man also den Fehler des Konstruktors im Programm identifizieren? Die „normalste“ Methode ist: eine Ausnahme auslösen. Der Fehler des Konstruktors bedeutet, dass die Konstruktion des Objekts fehlschlägt. Wie wird also mit diesem „halbtoten“ Objekt umgegangen, nachdem eine Ausnahme ausgelöst wurde? Hier ist es meiner Meinung nach notwendig, vor dem Lesen zu verstehen, wie C++ mit dieser Situation umgeht. In C++ wird der Destruktor nicht aufgerufen, nachdem der Konstruktor eine Ausnahme ausgelöst hat. Dieser Ansatz ist sinnvoll, da das Objekt zu diesem Zeitpunkt noch nicht vollständig konstruiert ist. Wenn der Konstruktor einige Vorgänge wie das Zuweisen von Speicher, das Öffnen von Dateien usw. durchgeführt hat, muss die C++-Klasse über eigene Mitglieder verfügen, um sich zu merken, welche Aktionen ausgeführt wurden. Dies ist natürlich für Klassenimplementierer sehr problematisch, daher vermeiden C++-Klassenimplementierer im Allgemeinen das Auslösen von Ausnahmen im Konstruktor (Sie können eine Mitgliedsfunktion wie Init und UnInit bereitstellen, die dem Konstruktor oder Klassenclient überlassen wird. Sie werden aufgerufen, um sie zu verarbeiten). Initialisierungsfehler). Die in jedem klassischen C++-Buch bereitgestellte Lösung besteht in der Verwendung intelligenter Zeiger (STLs Standardklasse auto_ptr). In Object Pascal wird dieses Problem sehr einfach und Programmierer müssen sich darüber keine Gedanken machen. Wenn eine Object Pascal-Klasse eine Ausnahme im Konstruktor auslöst, ruft der Compiler automatisch den Destruktor der Klasse auf (da der Destruktor nicht überladen werden darf, ist garantiert, dass es nur einen Destruktor gibt, sodass der Compiler nicht verwirrt wird . unter mehreren Destruktoren). Mitgliedsobjekte werden im Allgemeinen im Destruktor zerstört, und die Free()-Methode stellt sicher, dass der Destruktor nicht für Nullobjekte (d. h. Mitgliedsobjekte, die noch nicht erstellt wurden) aufgerufen wird, während der Code prägnant und schön gestaltet wird. es sorgt auch für Sicherheit. type MyClass = classPRivateFStr : PChar; // String-Zeiger publicconstructor Create();destructor Destroy(); override;end;constructor MyClass.Create();beginFStr := StrAlloc(10); // String-Zeiger im Konstruktor Allocate memoryStrCopy( FStr, 'ABCDEFGHI');raise Exception.Create('error'); Ausnahme wird ausgelöst, kein Grund, hahaend;destructor A.Destroy();beginStrDispose(FStr); // Speicher im Destruktor freigeben WriteLn('Free Resource');end;varObj : TMyClass;i : integer;begintryObj : = TMyClass.Create ();Obj.Free();WriteLn('Succeeded');exclusiveObj := nil;WriteLn('Failed');end;Read(i); // Bildschirm anhalten, um die laufenden Ergebnisse zu beobachten end In diesem Code löst der Konstruktor eine Ausnahme aus und das Ausführungsergebnis lautet: Free ResourceFailed at this time. Die Ausgabe „Free Resource“ wird vom Compiler erzeugt, der automatisch den Destruktor aufruft. Wenn Ihnen also die Klassendokumentation oder der Klassenautor mitteilt, dass der Klassenkonstruktor möglicherweise eine Ausnahme auslöst, denken Sie daran, diese mit try...exclusive! zu umschließen. Die unterschiedliche Art und Weise, wie C++ und Object Pascal mit von Konstruktoren ausgelösten Ausnahmen umgehen, verkörpert tatsächlich die Designideen der beiden Sprachen. C++ folgt dem Stil von C und legt den Fokus auf Effizienz. Alles wird dem Programmierer überlassen und der Compiler führt keine unnötigen Aktionen durch. Object Pascal übernimmt den Stil von Pascal und konzentriert sich auf die ästhetische Bedeutung des Programms. Der Compiler hilft Programmierern, komplexe Arbeiten abzuschließen.