Wie behandeln Sie falsche Werte in einen Konstruktor?
Bitte beachten Sie, dass dies eine Frage stellen Konstruktoren, nicht über Klassen, die sich mit der Zeit.
Angenommen ich habe eine Klasse wie folgt aus:
class Time
{
protected:
unsigned int m_hour;
unsigned int m_minute;
unsigned int m_second;
public:
Time(unsigned int hour, unsigned int minute, unsigned int second);
};
Während ich möchte ein gebaut werden erfolgreich, ich würde wollen, dass der Konstruktor von b zu scheitern.
Time a = Time(12,34,56);
Time b = Time(12,34,65); //second is larger than 60
Dies ist jedoch nicht möglich, da Konstruktoren nicht wieder alle Werte und wird immer erfolgreich sein.
Wie würde der Konstruktor dem Programm sagen, dass es ist nicht glücklich? Ich dachte daran, ein paar Methoden:
- den Konstruktor eine exception werfen, und Handler im aufrufenden Funktion zu behandeln.
- eine Flagge in die Klasse und setzen Sie ihn auf "true" nur, wenn die Werte akzeptabel sind, indem Sie den Konstruktor, und das Programm überprüft das flag sofort nach dem Bau.
- haben eine separate (wahrscheinlich statisch) - Funktion aufrufen, um zu überprüfen, die input-Parameter, die unmittelbar vor dem Aufruf des Konstruktors.
- redesign der Klasse, so dass es sein kann, konstruiert aus jedem input-Parameter.
Welche dieser Methoden ist am häufigsten in der Industrie? Oder ist es etwas, was ich vielleicht vergessen habe?
- mögliche Duplikate von How to handle-Fehler im Konstruktor in C++?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die typische Lösung ist zu werfen eine Ausnahme.
Die Logik dahinter ist die folgende: die Konstruktor ist eine Methode, die es vermag, ein Block des Speichers in ein gültiges Objekt. Entweder es gelingt (endet normalerweise) und Sie haben ein gültiges Objekt oder benötigen Sie einige non-ignorable Indikator für ein problem. Ausnahmen sind der einzige Weg, um das problem zu non-ignorable in C++.
Andere alternative, für die Vollständigkeit:
In Ihrem "Zeit" - Klasse, zum Beispiel, Sie haben könnte:
Stunden, Minuten und Sekunden wird begrenzt Werte. Zum Beispiel, mit dem (noch nicht)Boost Eingeschränkte Wert-Bibliothek:
Normal würd ich sagen (1). Aber wenn Sie eine finden, die Anrufer sind alle rund um den Bau mit try/catch, dann können Sie die statische helper-Funktion in (3) als gut, da mit ein bisschen Vorbereitung die Ausnahme kann gemacht werden, unmöglich.
Es ist eine weitere option, obwohl es hat erhebliche Konsequenzen für die Kodierung der Art, also sollte nicht angenommen werden, leicht,
5) nicht bestehen, die Parameter in den Konstruktor:
Er heißt zwei-Phasen-Konstruktion, und wird verwendet, gerade in Situationen, in denen es unerwünscht oder unmöglich für Konstruktoren, exceptions werfen. Code mit nothrow neu kompiliert werden mit
-fno-exceptions
ist wohl der klassische Fall. Sobald Sie gewöhnen, es ist etwas weniger nervig, als man zuerst vielleicht denkt.Time
implementieren sollten.static Time Time::create(unsigned int hour, unsigned int minute, unsigned int second, bool* is_ok);
Gibt es eine weitere Möglichkeit. Ich sage das nicht in irgendeiner Weise bevorzugt, nur hinzufügen, der Vollständigkeit halber:
Erstellen Sie eine factory-Funktion erzeugt eine Instanz der Klasse auf dem heap und liefert einen null-Zeiger, wenn die Erstellung fehlschlägt.
Dies ist nicht wirklich geeignet mit valuetype-Objekte wie z.B. Termine, aber es könnte nützlich sein, Anwendungen.
"Ausnahme von C 'Tor" ist nicht ein Wort mit vier Buchstaben.
Wenn ein Objekt nicht ordnungsgemäß erstellt werden, die C ' Tor sollte scheitern, weil Sie lieber nicht in den Bau, als wenn ein ungültiges Objekt.
In der Regel, Sie würden eine private/protected-Konstruktor und eine öffentliche, statische factory-Methode zum erstellen der Zeit-Objekt. Es ist nicht eine gute Idee, werfen eine exception in einem Konstruktor, weil es verheerende Auswirkungen auf die Vererbung. Auf diese Weise werden Ihre factory-Methode kann eine exception werfen, wenn nötig.
Ja. Design by Contract und lassen Sie die Voraussetzung Prüfung auf, und im Fehlerfall eine Ausnahme werfen. Keine ungültigen mal mehr.
Vielleicht. Akzeptabel, in komplexen Fällen aber wieder werfen, wenn Ihr die Kontrolle versagt.
Vielleicht. Dies ist ungefähr zu sagen, ob die input-Daten korrekt sind oder nicht, und kann nützlich sein, wenn sagen, das ist nicht trivial, aber siehe oben für , wie Sie reagieren im Falle von ungültigen Daten.
Nicht. Sie möchte grundsätzlich, vertagt das problem.
Nur zu erarbeiten, ein bisschen auf die Antworten von onebyone und Timbo. Wenn Leute die Möglichkeit besprechen, die Verwendung von Ausnahmen, in der Regel jemand schließlich sagt: "Ausnahmen in außergewöhnlichen Situationen."
Wie Sie sagen können, aus der die meisten der Antworten hier, wenn Sie einen Konstruktor fehlschlägt, dann die richtige Reaktion ist, um eine exception zu werfen. Aber in Ihrem Fall ist es nicht unbedingt, dass Sie nicht erstellen Sie das Objekt, es ist mehr, dass Sie nicht wollen, um es zu schaffen.
Wo die Werte ausgelesen werden, die aus einer externen Quelle (zB. eine Datei oder einen stream) gibt es eine gute chance, dass ungültige Werte empfangen werden, und in diesem Fall, dann ist es nicht wirklich eine außergewöhnliche situation.
Persönlich würde ich lean zur Validierung der Argumente vor der Erstellung des Zeit-Objekt (so etwas wie Timbo ' s Antwort) und ich hätte dann eine Behauptung in den Konstruktor, um zu überprüfen, dass diese Argumente gültig sind.
In dem Fall, dass Ihr Konstruktor muss eine Ressource (zB. reserviert Speicher), dann ist das, IMHO, eher um eine außergewöhnliche situation, und so würden Sie dann eine exception zu werfen.
Ich glaube nicht, dass Sie viel Auswahl.
Wenn Sie ungültige Eingabe Sie können nicht viel mehr machen, als signal an den Anrufer, als es ungültig ist. Sie können dann mit exception oder error-code.
Fehler-code im Konstruktor hätte übergeben werden müssen als Referenz-parameter, und als solche würde sich sehr akward.
Könnten Sie versuchen zu finden, wie könnten Sie überprüfen die Eingänge an der Quelle. Warum sind Sie immer ungültige Eingabe genau? Wie kann die Eingabe ungültig, etc.
Beispiel für Ihre date-Klasse sein würde, um zu erzwingen, dass der Benutzer (Nutzer des Programms), und geben Sie ein gültiges Datum (durch ihn zwingen, geben Sie es in einem Kalender-Typ GUI, zum Beispiel).
Könnte man auch versuchen, erstellen Sie eine Methode in Ihrer Klasse zu handhaben input-Validierung.
Mit, dass der Benutzer (Programmierer dieser Zeit) können Sie entweder nennen es vor dem Bau, und sicher sein, dass der Anruf nicht scheitern oder fallen zurück auf die Ausnahme, wenn der Benutzer nicht bestätigen.
Wenn die Leistung wichtig ist und Sie nicht möchten, rufen Sie die validate-Funktion zweimal (Benutzer aufrufen, dann im Konstruktor), ich denke, man könnte die named constructor idiom, um eine CheckedConstructor und ein UncheckedConstructor.
Dies ist zu Beginn architektonischen übertreiben, aber, ich denke.
In das Ende, es hängt von der Klasse und dem Anwendungsfall.
Erste ist der beste, Ausnahmen sind der beste Weg, um zu informieren die Klasse der Benutzer über den Fehler.
ist es nicht empfehlenswert, einen anderen Weg, denn wenn der Konstruktor zurückgibt, ohne Fehler, es heißt, Sie haben gebaut, ein Objekt richtig und können Sie es überall benutzen
Betrachten Sie eine Fabrik-Muster für die Generierung von Zeit-Objekte:
Dies macht die Annahme, dass Zeit hat: