Frage

Bei der Programmierung durch Vertrag eine Funktion oder Methode prüft zunächst, ob seine Voraussetzungen erfüllt sind, vor dem Start ihrer Verantwortung zu arbeiten, nicht wahr? Die beiden wichtigsten Möglichkeiten, um diese Kontrollen sind durch assert und von exception zu tun.

  1. assert nicht nur im Debug-Modus. Um sicherzustellen, dass es von entscheidender Bedeutung zu (Einheit) -Test alle separaten Vertrag Voraussetzungen, um zu sehen, ob sie tatsächlich scheitern.
  2. Ausnahme nicht im Debug-und Release-Modus. Dies hat den Vorteil, dass Debug-Verhalten ist identisch getestet Verhalten zu lösen, aber es verursacht eine Laufzeitleistungseinbuße.

Welches ist Ihrer Meinung nach vorzuziehen?

Siehe releated Frage hier

War es hilfreich?

Lösung

Die Deaktivierung in Release behauptet baut ist wie wenn man sagt: „Ich werde nie überhaupt in einem Release-Build irgendwelche Probleme habe“, was oft nicht der Fall ist. So behaupten soll nicht in einem Release-Build deaktiviert werden. Aber Sie wollen nicht auf das Release-Build abstürzt, wenn Fehler auftreten, entweder, nicht wahr?

So Ausnahmen verwenden und sie auch nutzen. Verwenden Sie eine gute, solide Ausnahme Hierarchie und sicherzustellen, dass Sie fangen und Sie einen Haken auf Ausnahme werfen in Ihrem Debugger, es zu fangen setzen können, und im Release-Modus können Sie den Fehler ausgleichen eher als ein straight-up zum Absturz bringen. Es ist der sicherere Weg zu gehen.

Andere Tipps

Als Faustregel ist, dass Sie Behauptungen verwenden sollen, wenn Sie versuchen, Ihre eigenen Fehler zu fangen, und Ausnahmen bei dem Versuch, andere Menschen Fehler zu fangen. Mit anderen Worten, sollten Sie Ausnahmen verwenden, um die Voraussetzungen für die öffentlichen API-Funktionen zu überprüfen und, wenn Sie alle Daten erhalten, die auf Ihr System extern sind. Sie sollten verwenden behauptet für die Funktionen oder Daten, die auf Ihrem System intern sind.

Das Prinzip I folgen, ist dies: Wenn eine Situation realistisch durch Codierung dann eine Assertion verwenden vermieden werden kann. Ansonsten eine Ausnahme verwenden.

Assertions sind dafür, dass der Vertrag eingehalten wird. Der Vertrag muss fair sein, so dass der Client in der Lage, sie erfüllt zu gewährleisten sein muss. Zum Beispiel können Sie in einem Vertrag fest, dass eine URL gültig sein muss, weil die Regeln über das, was ist und keine gültige URL ist bekannt sind und konsistent ist.

Ausnahmen sind für Situationen, die beide außerhalb der Kontrolle des Client und dem Server sind. Eine Ausnahme bedeutet, dass etwas schief gegangen ist, und es gibt nichts, was es zu vermeiden, hätte getan werden können. Zum Beispiel ist die Netzwerkverbindung außerhalb der Kontrolle von Anwendungen, so gibt es nichts, was getan werden kann, einen Netzwerkfehler zu vermeiden.

Ich mag hinzufügen, dass die Assertion / Exception Unterscheidung nicht wirklich der beste Weg ist, um darüber nachzudenken. Was Sie wirklich wollen, um zu denken, ist der Vertrag und wie sie durchgesetzt werden. In meinem URL Beispiel über diesem Beste, was zu tun ist, eine Klasse, die eine URL kapselt und ist entweder Null oder eine gültige URL. Es ist die Umwandlung einer Zeichenkette in eine URL, die den Vertrag erzwingt, und eine Ausnahme ausgelöst wird, wenn es ungültig ist. Ein Verfahren mit einem URL-Parameter ist viel deutlicher, daß ein Verfahren mit einem String-Parametern und eine Behauptung, die eine URL angibt.

ASSERTS sind für den Fang etwas Entwickler falsch gemacht hat (nicht nur sich selbst - ein anderer Entwickler in Ihrem Team auch). Wenn es sinnvoll ist, dass ein Benutzer Fehler diese Bedingung schaffen könnte, dann sollte es eine Ausnahme sein.

Ebenso denkt über die Folgen. Ein assert schließt typischerweise die App herunter. Wenn es eine realistische Erwartung ist, könnte, dass die Bedingung von gestellt werden, sollten Sie vielleicht eine Ausnahme verwenden.

Auf der anderen Seite, wenn das Problem nur sein aufgrund eines Programmierfehler dann zu einer Assertion verwenden, weil Sie es so schnell wie möglich wissen wollen. Eine Ausnahme könnte abgefangen und behandelt werden, und Sie würden darüber nie erfahren. Und ja, sollten Sie behauptet, in dem Freigabecode deaktivieren, da Sie die App wiederherstellen möchten, wenn auch nur die geringste Chance, es könnte. Auch wenn der Zustand Ihres Programms zutiefst den Benutzer gebrochen ist nur vielleicht in der Lage sein, ihre Arbeit zu speichern.

Es ist nicht ganz richtig, dass „assert nur im Debug-Modus nicht.“

In Object Oriented Software Construction, 2. Auflage von Bertrand Meyer, der Autor eine Tür zur Überprüfung Voraussetzungen im Release-Modus offen läßt. In diesem Fall geschieht was, wenn eine Behauptung nicht, dass ... eine Behauptung Verletzung Ausnahme ausgelöst wird! In diesem Fall gibt es keine Erholung von der Situation: etwas Nützliches obwohl getan werden könnte, und es ist, automatisch einen Fehlerbericht und in einigen Fällen zu generieren, die Anwendung neu starten

.

Die Motivation dahinter ist, dass Voraussetzungen der Regel billiger zu testen sind als Invarianten und Nachbedingungen, und dass in einigen Fällen der Richtigkeit und „Sicherheit“ in dem Release-Build ist wichtiger als Geschwindigkeit. dh Für viele Anwendungen Geschwindigkeit ist kein Problem, aber Robustheit (die Fähigkeit des Programms in einer sicheren Art und Weise zu verhalten, wenn sie ihr Verhalten nicht korrekt ist, dh, wenn ein Vertrag gebrochen wird) ist.

Wenn Sie immer Voraussetzung Prüfungen aktiviert lassen? Es hängt davon ab, ob. Es liegt an dir. Es gibt keine allgemeingültige Antwort. Wenn Sie Software für eine Bank machen, könnte es besser seine Ausführung mit einer alarmierenden Nachricht zu unterbrechen als $ 1.000.000 statt $ 1.000 zu übertragen. Aber was, wenn Sie die Programmierung eines Spiels? Vielleicht müssen Sie alle Geschwindigkeit, die Sie bekommen können, und wenn jemand bekommt 1000 Punkte statt 10 aufgrund eines Fehlers, der die Voraussetzungen nicht versteht (weil sie nicht aktiviert ist), Pech.

In beiden Fällen sind Sie bestens catched während des Tests, dass die Fehler haben sollte, und Sie sollten einen erheblichen Teil Ihres Tests durchführen aktiviert mit Behauptungen. Was hier diskutiert ist, was die beste Politik für die seltenen Fälle, in denen Voraussetzungen in einem Szenario, in Produktionscode fehlschlagen, die nicht früher aufgrund unvollständiger Tests nachgewiesen wurden.

Um es zusammenzufassen, Sie können Behauptungen haben und immer noch die Ausnahmen automatisch , wenn Sie sie aktiviert lassen - zumindest in Eiffel. Ich denke, das gleiche in C ++ zu tun, Sie müssen es selbst geben.

Siehe auch: Wann sollten Behauptungen im Produktionscode bleiben

Es gab eine riesige fädeln in Bezug auf die Aktivierung / Deaktivierung von Behauptungen in Release auf comp.lang.c baut ++. moderiert, die, wenn Sie ein paar Wochen haben, können Sie sehen, wie unterschiedlich die Meinungen dazu sind. :)

Im Gegensatz zu coppro , ich glaube, dass, wenn Sie nicht sicher sind, dass eine Behauptung in einem Release-Build deaktiviert wird, dann sollte es nicht eine Assertion gewesen. Assertions sind zum Schutz gegen Programm Invarianten gebrochen. In einem solchen Fall, soweit der Kunde Ihres Codes betroffen ist wird es eine von zwei möglichen Ergebnisse sein:

  1. Die mit irgendeiner Art von O Typ Ausfall in einer Aufforderung abzubrechen. (Ohne assert)
  2. über einen direkten Aufruf Die abzubrechen. (Mit assert)

Es gibt keinen Unterschied für den Benutzer, jedoch ist es möglich, dass die Behauptungen eine unnötigen Leistungskosten im Code hinzufügen, die in der überwiegenden Mehrzahl der Durchläufe vorhanden ist, wo der Code nicht ausfällt.

Die Antwort auf die Frage tatsächlich hängt viel mehr darüber, wer die Kunden der API sein. Wenn Sie eine Bibliothek schreiben eine API bereitstellt, dann müssen Sie irgendeine Form von Mechanismus Ihre Kunden zu informieren, dass sie die API falsch verwendet haben. Es sei denn, Sie zwei Versionen der Bibliothek liefern (eines mit behauptet, eine ohne), dann behauptet, ist sehr unwahrscheinlich, dass die geeignete Wahl.

Persönlich aber ich bin mir nicht sicher, dass ich entweder mit Ausnahmen für diesen Fall gehen würde. Ausnahmen sind besser geeignet, wo eine geeignete Form der Erholung erfolgen kann. Zum Beispiel kann es sein, dass Sie Speicher zuweisen versuchen. Wenn Sie eine ‚std :: bad_alloc‘ Ausnahme abfangen könnte es möglich sein, um Speicherplatz freizugeben und versuchen Sie es erneut.

Ich skizzierte meine Ansicht über den Stand der Angelegenheit hier: Wie validieren Sie einen internen Zustand des Objekts? . Im Allgemeinen Ihre Ansprüche geltend machen und von anderen wegen Verletzung werfen. Für Sperrung behauptet in Release-Builds, können Sie tun:

  • Deaktivieren für teure Kontrollen behauptet (wie Prüfen, ob ein Bereich bestellt wird)
  • Halten trivial Prüfungen aktiviert (wie für einen Null-Zeiger oder einen Booleschen Wert-Kontrolle)

Natürlich in Release-Builds, scheiterten Behauptungen und nicht abgefangene Ausnahmen sollten eine andere Art und Weise als in Debug-Builds behandelt werden (wo es nur std :: Abort nennen könnte). Schreiben Sie ein Protokoll der Fehler irgendwo (möglicherweise in einer Datei), sagen Sie dem Kunden, dass ein interner Fehler aufgetreten. Der Kunde in der Lage, Ihnen die Log-Datei zu senden.

Sie fragen, über den Unterschied zwischen Entwurfszeit und Laufzeitfehler.

behauptet sind Benachrichtigungen ‚hey Programmierung zu vereinfachen, ist gebrochen‘, sie sind da, um Sie von Fehlern zu erinnern, würden Sie nicht bemerkt haben, wenn sie geschehen ist.

Ausnahmen sind ‚hey Benutzer, Somethings schiefgegangen‘ Benachrichtigungen (natürlich können Sie kodieren, sie zu fangen, damit der Benutzer wird nie gesagt), aber diese sind so konzipiert, zur Laufzeit auftreten, wenn Joe Benutzer die App verwendet wird.

Also, wenn Sie denken, können Sie alle Ihre Fehler aus, nur Gebrauch Ausnahmen erhalten. Wenn Sie denken, Sie können nicht ..... Ausnahmen verwenden. Sie können weiterhin verwenden Debug die Anzahl der Ausnahmen weniger selbstverständlich machen behauptet.

Vergessen Sie nicht, dass viele der Voraussetzungen vom Benutzer gelieferten Daten werden, so dass Sie den Benutzer zu informieren, seine Daten waren nicht gut, einen guten Weg brauchen. Um das zu tun, müssen Sie oft Fehlerdaten auf dem Call-Stack auf die Bits zurück, mit denen er interagiert. Behauptet wird dann nicht sinnvoll sein -. Doppelt so wenn Ihre Anwendung ist n-tier

Schließlich würde ich weder verwenden - Fehlercodes sind weit überlegen für Fehler denken Sie regelmäßig auftreten. :)

Ich ziehe die zweite. Während Ihre Tests haben feine, Murphy laufen sagt, dass etwas Unerwartetes schief gehen. Anstatt also eine Ausnahme bei dem tatsächlichen fehlerhaften Methodenaufruf bekommen, erhalten Sie eine Nullpointer Tracing aus (oder äquivalent) 10 Stapelrahmen tiefer.

Die bisherigen Antworten sind richtig: Verwenden Sie Ausnahmen für öffentliche API-Funktionen. Die einzige Zeit, die Sie sich wünschen können diese Regel biegen ist, wenn der Scheck rechnerisch teuer ist. In diesem Fall Sie können legen es in einer Assertion.

Wenn Sie denken, Verletzung dieser Voraussetzung wahrscheinlich ist, halten Sie es als eine Ausnahme, oder die Voraussetzung Refactoring weg.

Sie sollten beide verwenden. Behauptet sind für Ihre Bequemlichkeit als Entwickler. Ausnahmen fangen Dinge, die Sie verpasst haben oder nicht während der Laufzeit erwarten.

Ich habe ans Herz gewachsen von Fehlerberichterstattung Funktionen glib statt plain old behauptet. Sie verhalten sich wie assert-Anweisungen, sondern das Programm Einhalt zu gebieten, kehren sie nur einen Wert und lassen Sie das Programm fortzusetzen. Es funktioniert überraschend gut, und als Bonus erhalten Sie zu sehen, was mit dem Rest des Programms geschieht, wenn eine Funktion nicht zurückgibt „was es soll“. Wenn es abstürzt, wissen Sie, dass Ihre Fehlerprüfung lax ist irgendwo anders auf der Straße.

In meinem letzten Projekt, habe ich diese Art von Funktionen Voraussetzung Prüfung zu implementieren, und wenn einer von ihnen versagt, würde ich einen Stack-Trace in die Protokolldatei drucken, sondern auf Laufen halten. Haben mich gerettet Tonnen Zeit Debuggen, wenn andere Leute würde ein Problem auftreten sollte, wenn meine Debug-Build ausgeführt wird.

#ifdef DEBUG
#define RETURN_IF_FAIL(expr)      do {                      \
 if (!(expr))                                           \
 {                                                      \
     fprintf(stderr,                                        \
        "file %s: line %d (%s): precondition `%s' failed.", \
        __FILE__,                                           \
        __LINE__,                                           \
        __PRETTY_FUNCTION__,                                \
        #expr);                                             \
     ::print_stack_trace(2);                                \
     return;                                                \
 };               } while(0)
#define RETURN_VAL_IF_FAIL(expr, val)  do {                         \
 if (!(expr))                                                   \
 {                                                              \
    fprintf(stderr,                                             \
        "file %s: line %d (%s): precondition `%s' failed.",     \
        __FILE__,                                               \
        __LINE__,                                               \
        __PRETTY_FUNCTION__,                                    \
        #expr);                                                 \
     ::print_stack_trace(2);                                    \
     return val;                                                \
 };               } while(0)
#else
#define RETURN_IF_FAIL(expr)
#define RETURN_VAL_IF_FAIL(expr, val)
#endif

Wenn ich Runtime Überprüfung der Argumente benötigen, würde ich dies tun:

char *doSomething(char *ptr)
{
    RETURN_VAL_IF_FAIL(ptr != NULL, NULL);  // same as assert(ptr != NULL), but returns NULL if it fails.
                                            // Goes away when debug off.

    if( ptr != NULL )
    {
       ...
    }

    return ptr;
}

Ich habe versucht, einige der anderen Antworten Synthetisierung hier mit meinen eigenen Ansichten.

Mit Behauptungen für Fälle, in denen Sie es in der Produktion deaktivieren wollen, zu verlassen verirrten sie in. Der einzige wirklichen Grund in der Produktion zu deaktivieren, aber nicht in der Entwicklung, ist das Programm zu beschleunigen. In den meisten Fällen wird diese Geschwindigkeit bis nicht signifikant sein, aber manchmal Code ist zeitkritisch oder der Test ist rechnerisch teuer. Wenn Code Mission kritisch ist, dann können Ausnahmen trotz der Verlangsamung am besten sein.

Wenn es eine echte Chance auf Heilung ist, verwenden Sie eine Ausnahme, da Behauptungen nicht aus geborgen werden entworfen. Zum Beispiel wird der Code nur selten von Programmierfehlern zu erholen entworfen, aber es ist so konzipiert, von Faktoren wie Netzwerkausfälle oder gesperrte Dateien wiederherzustellen. Fehler sollten nicht als Ausnahmen behandelt werden einfach für die außerhalb der Kontrolle des Programmierers zu sein. Vielmehr ist die Vorhersagbarkeit dieser Fehler, im Vergleich zu Codierung Fehler, macht sie zur Genesung liebenswürdiger.

Re Argument, dass es einfacher ist, Behauptungen zu debuggen: Der Stack-Trace aus einer richtig benannten Ausnahme ist so einfach wie eine Behauptung zu lesen. Guter Code soll nur bestimmte Arten von Ausnahmen fangen, so sollten Ausnahmen nicht unbemerkt bleiben aufgrund gefangen. Aber ich denke, Java manchmal zwingt Sie alle Ausnahmen zu fangen.

Siehe auch diese Frage :

  

ich einige Fälle, behauptet sind deaktiviert, wenn für die Freigabe zu bauen. Du könntest   keine Kontrolle über diese haben (sonst Sie behauptet bauen könnte   auf), so könnte es eine gute Idee sein, es so zu tun.

     

Das Problem mit „Korrektur“ die Eingangswerte ist, dass der Anrufer   bekommen nicht, was sie erwarten, und dies kann zu Problemen führen oder sogar   Abstürze in ganz anderen Teilen des Programms, das Debuggen eine machen   Alptraum.

     

ich in der Regel eine Ausnahme in der if-Anweisung werfen, die Rolle zu übernehmen   der assert, falls sie deaktiviert

assert(value>0);
if(value<=0) throw new ArgumentOutOfRangeException("value");
//do stuff

Die Faustregel für mich ist, dass die Verwendung Ausdrücke behauptet auf interne Fehler und Ausnahmen für externe Fehler zu finden. Sie können viel aus der folgenden Diskussion von Greg profitieren von hier .

  

Behaupten Ausdrücke werden verwendet, um zu finden Programmierfehler: entweder Fehler in der Logik des Programms selbst oder in Fehlern in seiner entsprechenden Umsetzung. Eine assert Bedingung überprüft, dass das Programm in einem definierten Zustand bleibt. A „definierten Zustand“ ist im Grunde ein, die mit dem Programm Annahmen übereinstimmt. Beachten Sie, dass ein „definierten Zustand“ für ein Programm kein „Idealzustand“ oder sogar „ein üblicher Zustand“ oder sogar ein „nützliches Zustand“ sein muss, sondern mehr auf, dass wichtige Punkt später.

     

Um zu verstehen, wie Behauptungen in ein Programm passen, sollten Sie eine Routine in   ein C ++ Programm, das etwa zu dereferenzieren Ein Zeiger ist. Nun sollte die   Routinetest, ob der Zeiger NULL ist vor dem dereferenzierenden oder   behaupten sollte, dass der Zeiger nicht NULL ist und dann gehen Sie vor und   dereferenzieren unabhängig?

     

Ich stelle mir vor, dass die meisten Entwickler wollen beides tun, fügen Sie die Assertion,   aber überprüfen Sie auch die Zeiger für einen NULL-Wert, um nicht zum Absturz bringen   sollte nicht die geltend gemachten Zustand. Auf der Oberfläche sowohl die Durchführung   testen und die Prüfung kann die klügste Entscheidung scheint

     

Im Gegensatz zu seinen geltend gemachten Bedingungen eines Programms Fehler (Ausnahmen) Behandlung bezieht sich nicht   um Fehler im Programm, sondern auf Eingaben erhält das Programm von seinem   Umgebung. Diese sind oft „Fehler“ auf jemandes Teil, wie ein Benutzer   Sie versuchen, auf ein Konto anmelden, ohne ein Passwort eingeben. Und   auch wenn der Fehler einen erfolgreichen Abschluss des Programms kann verhindern   Aufgabe gibt es keine Programmfehler. Das Programm schlägt fehl den Benutzer anmelden   ohne Passwort aufgrund eines externen Fehler - ein Fehler auf dem Benutzer   Teil. Wenn die Umstände waren anders, und der Benutzer in der typisierten   korrektes Passwort und das Programm nicht, sie zu erkennen; dann, obwohl   das Ergebnis immer noch das gleiche wäre, würde der Ausfall jetzt gehört   das Programm.

     

Der Zweck der Fehlerbehandlung (Ausnahmen) ist zweifach. Die erste ist, zu kommunizieren,   dem Benutzer (oder einen anderen Client), die in der Programm-Eingang ist ein Fehler   wurde erkannt und was es bedeutet. Das zweite Ziel ist die Wiederherstellung   Anwendung nach dem Fehler detektiert wird, zu einem gut definierten Zustand. Hinweis   dass das Programm selbst ist in dieser Situation nicht im Irrtum. Zugegeben, die   Programm kann in einem nicht idealen Zustand sein, oder auch ein Zustand, in dem tun   nichts nützlich, aber es ist keine Programmierung errorl. Andererseits,   da der Fehler Wiederherstellungszustand eine durch das Programm des erwarteten   Design, es iss ein, dass das Programm verarbeiten kann.

PS: Ihnen die ähnliche Frage überprüfen möchten. Ausnahme Vs Assertion

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