c++ Ist das böse?



c++ assert message (17)

Die Go Sprachersteller write :

Go liefert keine Assertions. Sie sind unbestreitbar bequem, aber unsere Erfahrung ist, dass Programmierer sie als eine Krücke verwenden, um zu vermeiden, über richtige Fehlerbehandlung und Berichterstattung nachzudenken. Eine ordnungsgemäße Fehlerbehandlung bedeutet, dass die Server nach nicht schwerwiegenden Fehlern weiterarbeiten, anstatt abzustürzen. Eine korrekte Fehleranzeige bedeutet, dass Fehler direkt und auf den Punkt gebracht werden, was den Programmierer davor bewahrt, eine große Unfallverfolgung zu interpretieren. Präzise Fehler sind besonders wichtig, wenn der Programmierer, der die Fehler sieht, nicht mit dem Code vertraut ist.

Was ist deine Meinung dazu?


Answer #1

Wenn die Behauptungen, über die Sie sprechen, bedeuten, dass das Programm übergibt und dann existiert, können Behauptungen sehr schlecht sein. Das heißt nicht, dass sie immer falsch sind, sie sind ein Konstrukt, das leicht missbraucht werden kann. Sie haben auch viele bessere Alternativen. Solche Dinge sind gute Kandidaten dafür, böse genannt zu werden.

Zum Beispiel sollte ein 3rd-Party-Modul (oder ein Modul wirklich) das aufrufende Programm fast nie verlassen. Dies gibt dem rufenden Programmierer keine Kontrolle darüber, welches Risiko das Programm in diesem Moment eingehen sollte. In vielen Fällen sind Daten so wichtig, dass sogar das Speichern beschädigter Daten besser ist als das Verlieren dieser Daten. Asserts können Sie zwingen, Daten zu verlieren.

Einige Alternativen zu behaupten:

  • Mit einem Debugger,
  • Konsole / Datenbank / andere Protokollierung
  • Ausnahmen
  • Andere Arten der Fehlerbehandlung

Einige Referenzen:

Selbst Leute, die für die Behauptung eintreten, denken, dass sie nur in der Entwicklung und nicht in der Produktion verwendet werden sollten:

Diese Person sagt, dass diese Option verwendet werden sollte, wenn das Modul möglicherweise Daten beschädigt hat, die nach dem Auslösen einer Ausnahme bestehen bleiben: http://www.advogato.org/article/949.html . Dies ist sicherlich ein vernünftiger Punkt, jedoch sollte ein externes Modul niemals vorschreiben, wie wichtig beschädigte Daten für das aufrufende Programm sind (durch Beenden von "für" sie). Der richtige Weg, dies zu umgehen, ist, eine Ausnahme auszulösen, die klarstellt, dass das Programm jetzt in einem inkonsistenten Zustand ist. Und da gute Programme meist aus Modulen bestehen (mit ein wenig Klebecode in der Hauptdatei), sind Behauptungen fast immer falsch.


Answer #2

Mein Problem mit diesen Antworten, die Assertion verteidigen, ist, dass niemand klar spezifiziert, was es von einem regulären fatalen Fehler unterscheidet , und warum eine Assert keine Untermenge einer Ausnahme sein kann . Jetzt, mit diesem gesagt, was, wenn die Ausnahme nie gefangen wird? Ist das eine Nomenklaturbestätigung? Und warum sollten Sie jemals eine Einschränkung in der Sprache auferlegen wollen, die eine Ausnahme auslösen kann, die / nichts / kann?


Answer #3

Kurze Antwort: Nein, ich glaube, Behauptungen können nützlich sein


Answer #4

Ja, Behauptungen sind böse.

Oft werden sie an Orten verwendet, an denen eine korrekte Fehlerbehandlung verwendet werden sollte. Gewöhnen Sie sich von Anfang an daran, Fehler in der Produktionsqualität zu schreiben!

In der Regel behindern sie das Schreiben von Komponententests (es sei denn, Sie schreiben ein benutzerdefiniertes Assert, das mit Ihrem Testkabelbaum interagiert). Dies liegt oft daran, dass sie dort verwendet werden, wo eine korrekte Fehlerbehandlung verwendet werden sollte.

Meistens werden sie aus Release-Builds kompiliert, was bedeutet, dass keiner ihrer "Tests" verfügbar ist, wenn Sie den Code ausführen, den Sie tatsächlich veröffentlichen; Angesichts der Tatsache, dass in Multi-Thread-Situationen die schlimmsten Probleme oft nur in Release-Code auftreten, kann dies schlecht sein.

Manchmal sind sie eine Krücke für ansonsten gebrochene Designs; dh das Design des Codes erlaubt es einem Benutzer, ihn so aufzurufen, dass er nicht aufgerufen werden sollte und die Assert "verhindert" dies. Fix das Design!

Ich habe darüber 2005 in meinem Blog hier mehr geschrieben: http://www.lenholgate.com/blog/2005/09/assert-is-evil.html


Answer #5

Ich benutze niemals assert (), Beispiele zeigen normalerweise so etwas:

int* ptr = new int[10];
assert(ptr);

Das ist schlecht, ich mache das nie, was ist, wenn mein Spiel eine Menge Monster verteilt? Warum sollte ich das Spiel abstürzen, stattdessen sollten Sie die Fehler anmutig behandeln, also tun Sie etwas wie:

CMonster* ptrMonsters = new CMonster[10];
if(ptrMonsters == NULL) // or u could just write if(!ptrMonsters)
{
    // we failed allocating monsters. log the error e.g. "Failed spawning 10 monsters".
}
else
{
    // initialize monsters.
}

Answer #6

Behauptungen sind nicht böse, aber sie können leicht missbraucht werden. Ich stimme der Aussage zu, dass "Behauptungen oft als eine Krücke verwendet werden, um zu vermeiden, über eine korrekte Fehlerbehandlung und Berichterstattung nachzudenken". Ich habe das oft gesehen.

Persönlich verwende ich gerne Behauptungen, weil sie Annahmen dokumentieren, die ich beim Schreiben meines Codes gemacht habe. Wenn diese Annahmen unter Beibehaltung des Codes verletzt werden, kann das Problem während des Tests erkannt werden. Allerdings mache ich den Punkt, dass ich jedes Assert aus meinem Code streiche, wenn ich einen Produktions-Build mache (dh mit #ifdefs). Indem ich die Behauptungen im Produktionsaufbau streiche, eliminiere ich das Risiko, dass jemand sie als Krücke mißbraucht.

Es gibt auch ein anderes Problem mit Behauptungen. Assertions werden nur zur Laufzeit überprüft. Es ist jedoch häufig der Fall, dass die Überprüfung, die Sie durchführen möchten, zur Kompilierungszeit ausgeführt werden konnte. Es ist vorzuziehen, ein Problem zur Kompilierzeit zu erkennen. Für C ++ - Programmierer bietet Boost BOOST_STATIC_ASSERT, mit dem Sie dies tun können. Für C-Programmierer beschreibt dieser Artikel ( Linktext ) eine Technik, mit der Assertionen zur Kompilierungszeit ausgeführt werden können.

Zusammengefasst lautet die Faustregel, die ich befolge: Verwenden Sie keine Assertions in einem Produktions-Build und verwenden Sie, wenn möglich, nur Assertionen für Dinge, die zur Kompilierungszeit nicht verifiziert werden können (dh zur Laufzeit überprüft werden müssen).


Answer #7

Durch diese Logik sind Breakpoints auch böse.

Asserts sollten als Debugging-Hilfe und sonst nichts verwendet werden. "Evil" ist, wenn Sie versuchen, sie anstelle der Fehlerbehandlung zu verwenden.

Asserts helfen Ihnen, dem Programmierer, Probleme zu erkennen und zu beheben, die nicht existieren dürfen, und zu überprüfen, ob Ihre Annahmen wahr sind.

Sie haben nichts mit der Fehlerbehandlung zu tun, aber leider werden sie von einigen Programmierern als solche missbraucht und dann als "böse" deklariert.


Answer #8

assert ist sehr nützlich und kann Ihnen beim Auftreten unerwarteter Fehler viel Rückschritt ersparen, indem Sie das Programm bei den ersten Anzeichen von Problemen anhalten.

Auf der anderen Seite ist es sehr leicht zu missbrauchen assert .

int quotient(int a, int b){
    assert(b != 0);
    return a / b;
}

Die richtige, korrekte Version wäre etwa:

bool quotient(int a, int b, int &result){
    if(b == 0)
        return false;

    result = a / b;
    return true;
}

Also ... auf lange Sicht ... im großen Bild ... Ich muss zustimmen, dass assert missbraucht werden können. Das mache ich die ganze Zeit.


Answer #9

Ich gebe zu, behauptet zu haben, ohne über die richtige Fehlerberichterstattung nachzudenken. Das hilft jedoch nicht, dass sie bei korrekter Anwendung sehr hilfreich sind.

Sie sind besonders nützlich, wenn Sie dem Prinzip "Crash Early" folgen möchten. Angenommen, Sie implementieren einen Referenzzählungsmechanismus. An bestimmten Stellen in Ihrem Code wissen Sie, dass der Refcount Null oder Eins sein sollte. Und wenn der Refcount falsch ist, wird das Programm nicht sofort abstürzen, sondern während der nächsten Nachrichtenschleife wird es schwierig sein herauszufinden, warum etwas schief gelaufen ist. Eine Bestätigung wäre hilfreich gewesen, um den Fehler näher an seinem Ursprung zu erkennen.


Answer #10

assert wird für die Fehlerbehandlung missbraucht, weil es weniger tippt.

Als Sprachdesigner sollten sie eher sehen, dass eine korrekte Fehlerbehandlung mit noch weniger Tipparbeit möglich ist. Das Ausschließen von Assert, weil Ihr Ausnahmemechanismus ausführlich ist, ist nicht die Lösung. Oh warte, Go hat auch keine Ausnahmen. Schade :)


Answer #11

Das kommt oft auf, und ich denke, ein Problem, das die Abwehr von Behauptungen verwirrend macht, ist, dass sie oft auf der Überprüfung von Argumenten basieren. Betrachten Sie dieses andere Beispiel, wann Sie eine Assertion verwenden könnten:

build-sorted-list-from-user-input(input)

    throw-exception-if-bad-input(input)

    ...

    //build list using algorithm that you expect to give a sorted list

    ...

    assert(is-sorted(list))

end

Sie verwenden eine Ausnahme für die Eingabe, weil Sie erwarten, dass Sie manchmal schlechte Eingaben erhalten. Sie behaupten, dass die Liste sortiert ist, um Ihnen zu helfen, einen Fehler in Ihrem Algorithmus zu finden, den Sie per Definition nicht erwarten. Die Assertion befindet sich nur im Debug-Build. Obwohl die Prüfung teuer ist, macht es Ihnen nichts aus, dies bei jedem einzelnen Aufruf der Routine zu tun.

Sie müssen Ihren Produktionscode noch in der Einheit testen, aber das ist eine andere und ergänzende Methode, um sicherzustellen, dass Ihr Code korrekt ist. Komponententests stellen sicher, dass Ihre Routine ihrer Schnittstelle entspricht, während Assertionen eine feinere Methode darstellen, um sicherzustellen, dass Ihre Implementierung genau das tut, was Sie von ihr erwarten.


Answer #12

Ich bevorzuge es, Code zu vermeiden, der beim Debuggen und Freigeben verschiedene Dinge tut.

Es ist jedoch nützlich, den Debugger unter einer Bedingung zu brechen und alle Datei- / Zeileninformationen zu haben, auch den genauen Ausdruck und den genauen Wert.

Eine Assertion zu haben, die "die Bedingung nur im Debug auswerten würde" könnte eine Leistungsoptimierung sein und daher nur in 0,0001% der Programme nützlich sein - wo die Leute wissen, was sie tun. In allen anderen Fällen ist dies schädlich, da der Ausdruck den Zustand des Programms ändern kann:

assert(2 == ShroedingersCat.GetNumEars()); würde das Programm verschiedene Dinge in Debug und Release machen.

Wir haben eine Reihe von Assert-Makros entwickelt, die eine Ausnahme auslösen und dies sowohl in der Debug- als auch in der Release-Version tun. Zum Beispiel THROW_UNLESS_EQ(a, 20); würde eine Ausnahme mit what () - Nachricht mit Datei, Zeile und den tatsächlichen Werten von a usw. auslösen. Nur ein Makro hätte dafür die Macht. Der Debugger kann so konfiguriert werden, dass er beim "Auslösen" des spezifischen Ausnahmetyps bricht.


Answer #13

Ich benutze gerne viel zu behaupten. Ich finde es sehr nützlich, wenn ich zum ersten Mal Anwendungen erstelle (vielleicht für eine neue Domäne). Anstatt eine sehr ausgefallene Fehlerüberprüfung zu machen (die ich als vorzeitige Optimierung betrachten würde), code ich schnell und ich füge eine Menge Behauptungen hinzu. Nachdem ich mehr darüber weiß, wie die Dinge funktionieren, überschreibe und entferne ich einige der Behauptungen und ändere sie für eine bessere Fehlerbehandlung.

Aufgrund von Behauptungen verbringe ich viel weniger Zeit mit dem Programmieren / Debuggen von Programmen.

Ich habe auch bemerkt, dass die Behauptungen mir helfen, an viele Dinge zu denken, die meine Programme brechen könnten.


Answer #14

Nein, Assert ist nicht falsch, solange Sie es wie vorgesehen verwenden.

Das heißt, es sollte Fälle erfassen, die beim Debuggen "nicht passieren können", im Gegensatz zur normalen Fehlerbehandlung.

  • Assert: Ein Fehler in der Logik des Programms selbst.
  • Fehlerbehandlung: Ein fehlerhafter Eingabe- oder Systemstatus, der nicht auf einen Fehler im Programm zurückzuführen ist.

Answer #15

Ich mag es nicht besonders. Ich würde nicht so weit gehen und sagen, dass sie böse sind.

Im Grunde wird ein Assert dasselbe tun wie eine ungeprüfte Ausnahme, die einzige Ausnahme ist, dass das Assert (normalerweise) nicht für das Endprodukt gehalten werden sollte.

Wenn Sie ein Sicherheitsnetz für sich selbst bauen, während Sie das System debuggen und aufbauen, warum sollten Sie dieses Sicherheitsnetz für Ihren Kunden oder Ihren Support-Helpdesk oder für jeden, der die Software, die Sie gerade erstellen, verwenden, verweigern. Verwenden Sie Ausnahmen ausschließlich für Behauptungen und Ausnahmesituationen. Durch die Erstellung einer geeigneten Ausnahmehierarchie können Sie sehr schnell voneinander unterscheiden. Abgesehen von dieser Zeit bleibt das Assert an seinem Platz und kann wertvolle Informationen im Falle eines Fehlers liefern, der andernfalls verloren gehen würde.

Ich verstehe also die Ersteller von Go vollständig, indem ich alles zusammen zurückhalte und Programmierer dazu zwinge, Ausnahmen zu verwenden, um mit der Situation umzugehen. Es gibt eine einfache Erklärung dafür, Ausnahme sind nur ein besserer Mechanismus für den Job, warum bleiben Sie mit den archaischen Behauptungen?


Answer #16

Als zusätzliche Information bietet go eine integrierte Funktion panic . Dies kann anstelle von assert . Z.B

if x < 0 {
    panic("x is less than 0");
}

panic druckt die Stack-Trace, also hat es in gewisser Weise den Zweck zu assert .


Answer #17

Nein, weder goto noch assert sind böse. Aber beide können missbraucht werden.

Assert ist für Plausibilitätsprüfungen. Dinge, die das Programm töten sollten, wenn sie nicht korrekt sind. Nicht zur Validierung oder als Ersatz für die Fehlerbehandlung.





assert