it-swarm.com.de

Ist es sinnvoll, jeden einzelnen dereferenzierten Zeiger auf Null zu setzen?

Bei einem neuen Job wurde ich in Codeüberprüfungen für Code wie diesen markiert:

PowerManager::PowerManager(IMsgSender* msgSender)
  : msgSender_(msgSender) { }

void PowerManager::SignalShutdown()
{
    msgSender_->sendMsg("shutdown()");
}

Mir wurde gesagt, dass die letzte Methode lauten sollte:

void PowerManager::SignalShutdown()
{
    if (msgSender_) {
        msgSender_->sendMsg("shutdown()");
    }
}

d.h. ich muss setze einen NULL Schutz um das msgSender_ Variable, obwohl es sich um ein privates Datenelement handelt. Es fällt mir schwer, mich davon abzuhalten, Sprengsätze zu verwenden, um zu beschreiben, wie ich über dieses Stück „Weisheit“ fühle. Wenn ich nach einer Erklärung frage, bekomme ich eine Litanei von Horrorgeschichten darüber, wie ein Junior-Programmierer eines Jahres verwirrt darüber war, wie eine Klasse funktionieren sollte, und löschte versehentlich ein Mitglied, das er nicht haben sollte (und stellte es auf NULL danach anscheinend) und die Dinge explodierten direkt nach einer Produktveröffentlichung im Feld, und wir haben "auf die harte Tour gelernt, vertrauen Sie uns", dass es besser ist, nur NULL zu überprüfen alles.

Für mich fühlt sich das wie Frachtkultprogrammierung an, schlicht und einfach. Ein paar gut gemeinte Kollegen versuchen ernsthaft, mir zu helfen, es zu bekommen und zu sehen, wie dies mir hilft, robusteren Code zu schreiben, aber ... ich kann nicht anders, als das Gefühl zu haben, dass sie es nicht verstehen .

Ist es für einen Codierungsstandard sinnvoll, zu verlangen, dass jeder einzelne Zeiger, der in einer Funktion dereferenziert wurde, zuerst auf NULL überprüft wird - sogar auf private Datenelemente? (Hinweis: Um einen gewissen Kontext zu schaffen, stellen wir ein Unterhaltungselektronikgerät her, kein Flugsicherungssystem oder ein anderes Produkt, bei dem Fehler gleich Menschen sterben.)

[~ # ~] edit [~ # ~] : Im obigen Beispiel ist das msgSender_ Mitarbeiter ist nicht optional. Wenn es jemals NULL ist, weist es auf einen Fehler hin. Der einzige Grund, warum es an den Konstruktor übergeben wird, ist, dass PowerManager mit einer Schein-Unterklasse IMsgSender getestet werden kann.

[~ # ~] Zusammenfassung [~ # ~] : Es gab einige wirklich gute Antworten auf diese Frage, danke an alle. Ich habe den von @aaronps hauptsächlich wegen seiner Kürze akzeptiert. Es scheint eine ziemlich breite allgemeine Übereinstimmung zu bestehen, dass:

  1. Das Mandatieren von NULL Wachen für jeden einzelnen dereferenzierten Zeiger ist übertrieben, aber
  2. Sie können die gesamte Debatte umgehen, indem Sie stattdessen (wenn möglich) eine Referenz oder einen Zeiger const verwenden
  3. assert -Anweisungen sind eine aufschlussreichere Alternative zu NULL -Wachen, um zu überprüfen, ob die Voraussetzungen einer Funktion erfüllt sind.
66
evadeflow

Es kommt auf den "Vertrag" an:

Wenn PowerManager MUSS ein gültiges IMsgSender haben, prüfen Sie niemals auf null, lassen Sie es früher sterben.

Wenn es andererseits KANN ein IMsgSender haben, müssen Sie jedes Mal überprüfen, wie einfach das ist.

Abschließender Kommentar zur Geschichte des Junior-Programmierers, das Problem ist eigentlich das Fehlen von Testverfahren.

66
aaronps

Ich denke, der Code sollte lauten:

PowerManager::PowerManager(IMsgSender* msgSender)
  : msgSender_(msgSender)
{
    assert(msgSender);
}

void PowerManager::SignalShutdown()
{
    assert(msgSender_);
    msgSender_->sendMsg("shutdown()");
}

Dies ist tatsächlich besser als das Schützen von NULL, da es sehr deutlich macht, dass die Funktion niemals aufgerufen werden sollte, wenn msgSender_ NULL ist. Es stellt auch sicher, dass Sie bemerken, wenn dies passiert.

Die gemeinsame "Weisheit" Ihrer Kollegen ignoriert diesen Fehler stillschweigend mit unvorhersehbaren Ergebnissen.

Im Allgemeinen lassen sich Fehler leichter beheben, wenn sie näher an ihrer Ursache erkannt werden. In diesem Beispiel würde der vorgeschlagene NULL-Schutz dazu führen, dass eine Meldung zum Herunterfahren nicht gesetzt wird, was zu einem erkennbaren Fehler führen kann oder nicht. Es würde Ihnen schwerer fallen, rückwärts zur Funktion SignalShutdown zu arbeiten, als wenn die gesamte Anwendung gerade gestorben wäre und einen handlichen Dandy-Backtrace oder Core-Dump erzeugt, der direkt auf SignalShutdown() verweist.

Es ist ein wenig eingängig, aber ein Absturz, sobald etwas nicht stimmt, macht Ihren Code robuster. Das liegt daran, dass Sie tatsächlich finden die Probleme haben und dazu neigen, auch sehr offensichtliche Ursachen zu haben.

77
Kristof Provost

Wenn msgSender darf niemalsnull sein, sollten Sie die Prüfung null nur im Konstruktor ablegen. Dies gilt auch für alle anderen Eingaben in die Klasse - setzen Sie die Integritätsprüfung an den Punkt des Eintritts in die 'Modul'-Klasse, Funktion usw.

Meine Faustregel lautet, Integritätsprüfungen zwischen Modulgrenzen durchzuführen - in diesem Fall der Klasse. Darüber hinaus sollte eine Klasse so klein sein, dass es möglich ist, die Integrität der Lebenszeiten der Klassenmitglieder schnell mental zu überprüfen, um sicherzustellen, dass Fehler wie unsachgemäße Löschungen/Nullzuweisungen verhindert werden. Bei der Nullprüfung, die im Code in Ihrem Beitrag durchgeführt wird, wird davon ausgegangen, dass bei einer ungültigen Verwendung dem Zeiger tatsächlich Null zugewiesen wird - was nicht immer der Fall ist. Da "ungültige Verwendung" von Natur aus impliziert, dass keine Annahmen über regulären Code zutreffen, können wir nicht sicher sein, alle Arten von Zeigerfehlern zu erfassen - zum Beispiel ein ungültiges Löschen, Inkrementieren usw.

Wenn Sie sicher sind, dass das Argument niemals null sein kann, sollten Sie abhängig von Ihrer Verwendung der Klasse Referenzen verwenden. Verwenden Sie andernfalls std::unique_ptr Oder std::shared_ptr Anstelle eines Rohzeigers.

30
Max

Nein, es ist nicht sinnvoll, jede einzelne Zeiger-Dereferenzierung für den Zeiger zu überprüfen, der NULL ist.

Nullzeigerprüfungen sind für Funktionsargumente (einschließlich Konstruktorargumente) hilfreich, um sicherzustellen, dass die Voraussetzungen erfüllt sind, oder um geeignete Maßnahmen zu ergreifen, wenn kein optionaler Parameter angegeben wird, und um die Invariante einer Klasse zu überprüfen, nachdem Sie die Interna der Klasse verfügbar gemacht haben. Wenn der einzige Grund dafür, dass ein Zeiger NULL geworden ist, das Vorhandensein eines Fehlers ist, macht es keinen Sinn, dies zu überprüfen. Dieser Fehler hätte genauso gut den Zeiger auf einen anderen ungültigen Wert setzen können.

Wenn ich mit einer Situation wie Ihrer konfrontiert wäre, würde ich zwei Fragen stellen:

  • Warum wurde der Fehler dieses Junior-Programmierers nicht vor der Veröffentlichung abgefangen? Zum Beispiel bei einer Codeüberprüfung oder in der Testphase? Die Markteinführung eines fehlerhaften Unterhaltungselektronikgeräts kann genauso kostspielig sein (wenn Sie Marktanteile und den guten Willen berücksichtigen) wie die Freigabe eines fehlerhaften Geräts, das in einer sicherheitskritischen Anwendung verwendet wird. Daher würde ich erwarten, dass das Unternehmen das Testen ernst nimmt und andere QS-Aktivitäten.
  • Wenn die Nullprüfung fehlschlägt, welche Fehlerbehandlung soll ich einführen, oder könnte ich einfach assert(msgSender_) anstelle der Nullprüfung schreiben? Wenn Sie nur den Null-Check-in eingeben, haben Sie möglicherweise einen Absturz verhindert, aber möglicherweise eine schlimmere Situation geschaffen, da die Software unter der Voraussetzung fortgesetzt wird, dass ein Vorgang stattgefunden hat, während dieser Vorgang in Wirklichkeit übersprungen wurde. Dies kann dazu führen, dass andere Teile der Software instabil werden.

In diesem Beispiel geht es anscheinend mehr um die Objektlebensdauer als darum, ob ein Eingabeparameter null ist †. Da Sie erwähnen, dass PowerManagerimmer ein gültiges IMsgSender haben muss, erscheint mir die Übergabe des Arguments per Zeiger (wodurch die Möglichkeit eines Nullzeigers ermöglicht wird) als Entwurf Fehler††.

In solchen Situationen würde ich es vorziehen, die Schnittstelle so zu ändern, dass die Anforderungen des Anrufers durch die Sprache erzwungen werden:

PowerManager::PowerManager(const IMsgSender& msgSender)
  : msgSender_(msgSender) {}

void PowerManager::SignalShutdown() {
    msgSender_->sendMsg("shutdown()");
}

Wenn Sie es auf diese Weise umschreiben, muss PowerManager für die gesamte Lebensdauer einen Verweis auf IMsgSender enthalten. Dies wiederum legt auch eine implizite Anforderung fest, dass IMsgSender länger als PowerManager leben muss, und macht die Notwendigkeit von Nullzeigerprüfungen oder Zusicherungen in PowerManager zunichte.

Sie können dasselbe auch mit einem intelligenten Zeiger (über Boost oder C++ 11) schreiben, um IMsgSender explizit zu zwingen, länger als PowerManager zu leben:

PowerManager::PowerManager(std::shared_ptr<IMsgSender> msgSender) 
  : msgSender_(msgSender) {}

void PowerManager::SignalShutdown() {
    // Here, we own a smart pointer to IMsgSender, so even if the caller
    // destroys the original pointer, we still have a valid copy
    msgSender_->sendMsg("shutdown()");
}

Diese Methode wird bevorzugt, wenn es möglich ist, dass die Lebensdauer von IMsgSender nicht länger als die von PowerManager (d. H. x = new IMsgSender(); p = new PowerManager(*x);) garantiert werden kann.

† In Bezug auf Zeiger: Die zügellose Nullprüfung erschwert das Lesen von Code und verbessert nicht die Stabilität (es verbessert das Erscheinungsbild der Stabilität, was viel schlimmer ist).

Irgendwo hat jemand eine Adresse für den Speicher bekommen, die das IMsgSender enthält. Es liegt in der Verantwortung dieser Funktion, sicherzustellen, dass die Zuordnung erfolgreich war (Überprüfung der Bibliotheksrückgabewerte oder ordnungsgemäße Behandlung von std::bad_alloc - Ausnahmen), um keine ungültigen Zeiger weiterzugeben.

Da das PowerManager das IMsgSender nicht besitzt (es leiht es nur für eine Weile aus), ist es nicht dafür verantwortlich, diesen Speicher zuzuweisen oder zu zerstören. Dies ist ein weiterer Grund, warum ich die Referenz bevorzuge.

†† Da Sie neu in diesem Job sind, gehe ich davon aus, dass Sie vorhandenen Code hacken. Mit Konstruktionsfehler meine ich, dass der Fehler in dem Code liegt, mit dem Sie arbeiten. Daher markieren sich die Leute, die Ihren Code kennzeichnen, weil er nicht nach Nullzeigern sucht, wirklich selbst, um Code zu schreiben, der Zeiger erfordert :)

9
Seth

Wie bei Ausnahmen sind Schutzbedingungen nur dann nützlich, wenn Sie wissen, wie Sie den Fehler beheben können, oder wenn Sie eine aussagekräftigere Ausnahmemeldung geben möchten.

Das Verschlucken eines Fehlers (ob als Ausnahme oder als Wachkontrolle) ist nur dann das Richtige, wenn der Fehler keine Rolle spielt. Der häufigste Ort, an dem ich sehe, dass Fehler verschluckt werden, ist der Fehlerprotokollierungscode. Sie möchten eine App nicht zum Absturz bringen, weil Sie keine Statusmeldung protokollieren konnten.

Jedes Mal, wenn eine Funktion aufgerufen wird und dies kein optionales Verhalten ist, sollte sie laut und nicht lautlos fehlschlagen.

Edit : Wenn Sie über Ihre Junior-Programmierer-Geschichte nachdenken, klingt es so, als ob ein privates Mitglied auf null gesetzt wurde, als dies niemals erlaubt sein sollte. Sie hatten ein Problem mit unangemessenem Schreiben und versuchen, es durch Validieren beim Lesen zu beheben. Das ist rückwärts. Zu dem Zeitpunkt, an dem Sie es identifizieren, ist der Fehler bereits aufgetreten. Die Code-Review/Compiler-durchsetzbare Lösung dafür sind keine Schutzbedingungen, sondern Getter und Setter oder Const-Mitglieder.

8
jmoreno

Wie andere angemerkt haben, hängt dies davon ab, ob msgSender legitim NULL sein kann oder nicht. Im Folgenden wird davon ausgegangen, dass niemals NULL sein sollte.

void PowerManager::SignalShutdown()
{
    if (!msgSender_)
    {
       throw SignalException("Shut down failed because message sender is not set.");
    }

    msgSender_->sendMsg("shutdown()");
}

Die von den anderen in Ihrem Team vorgeschlagene "Korrektur" verstößt gegen das Dead Programs Tell No Lies -Prinzip. Bugs sind so wie sie sind wirklich schwer zu finden. Eine Methode, die ihr Verhalten aufgrund eines früheren Problems stillschweigend ändert, macht es nicht nur schwierig, den ersten Fehler zu finden, sondern fügt auch einen eigenen zweiten Fehler hinzu.

Der Junior hat Chaos angerichtet, indem er nicht nach einer Null gesucht hat. Was ist, wenn dieser Code Chaos anrichtet, indem er weiterhin in einem undefinierten Zustand ausgeführt wird (Gerät ist eingeschaltet, aber das Programm "denkt", dass es ausgeschaltet ist)? Möglicherweise führt ein anderer Teil des Programms etwas aus, das nur dann sicher ist, wenn das Gerät ausgeschaltet ist.

Mit beiden Ansätzen werden stille Fehler vermieden:

  1. Verwenden Sie Asserts wie von diese Antwort vorgeschlagen, aber stellen Sie sicher, dass sie im Produktionscode aktiviert sind. Dies könnte natürlich zu Problemen führen, wenn andere Zusicherungen mit der Annahme verfasst würden, dass sie in der Produktion nicht verfügbar sind.

  2. Wirf eine Ausnahme aus, wenn sie null ist.

7
poke

Ich bin damit einverstanden, die Null im Konstruktor einzufangen. Wenn das Mitglied in der Kopfzeile wie folgt deklariert ist:

IMsgSender* const msgSender_;

Dann kann der Zeiger nach der Initialisierung nicht mehr geändert werden. Wenn er bei der Erstellung in Ordnung war, ist er für die Lebensdauer des Objekts, das ihn enthält, in Ordnung. (Das Objekt, auf das to zeigt, wird not const sein.)

5

Dies ist absolut Gefährlich!

Ich habe unter einem erfahrenen Entwickler in einer C-Codebasis mit den schlechtesten "Standards" gearbeitet, die auf dasselbe drängten, um blind alle Zeiger auf Null zu überprüfen. Der Entwickler würde am Ende folgende Dinge tun:

// Pre: vertex should never be null.
void transform_vertex(Vertex* vertex, ...)
{
    // Inserted by my "wise" co-worker.
    if (!vertex)
        return;
    ...
}

Ich habe einmal versucht, eine solche Überprüfung der Vorbedingung einmal in einer solchen Funktion zu entfernen und durch ein assert zu ersetzen, um zu sehen, was passieren würde.

Zu meinem Entsetzen fand ich Tausende von Codezeilen in der Codebasis, die dieser Funktion Nullen übergaben, aber wo die Entwickler, wahrscheinlich verwirrt, herumgingen und einfach mehr Code hinzufügten, bis die Dinge funktionierten.

Zu meinem weiteren Entsetzen stellte ich fest, dass dieses Problem an allen möglichen Stellen in der Codebasis weit verbreitet war und nach Nullen suchte. Die Codebasis war über Jahrzehnte gewachsen, um sich auf diese Überprüfungen zu verlassen, um selbst die am explizitesten dokumentierten Voraussetzungen stillschweigend verletzen zu können. Durch Entfernen dieser tödlichen Überprüfungen zugunsten von asserts würden alle logischen menschlichen Fehler über Jahrzehnte in der Codebasis aufgedeckt und wir würden darin ertrinken.

Es dauerte nur zwei scheinbar unschuldige Codezeilen wie diese + Zeit und ein Team, um am Ende tausend angesammelte Fehler zu maskieren.

Dies sind die Arten von Praktiken, die dazu führen, dass Fehler von anderen vorhandenen Fehlern abhängen, damit die Software funktioniert. Es ist ein Alptraumszenario . Außerdem wird jeder logische Fehler im Zusammenhang mit der Verletzung solcher Voraussetzungen auf mysteriöse Weise eine Million Codezeilen von der tatsächlichen Site entfernt angezeigt, an der der Fehler aufgetreten ist, da all diese Nullprüfungen nur den Fehler verbergen und den Fehler verbergen, bis wir einen Ort erreichen, der vergessen hat den Fehler zu verbergen.

Einfach blind an jedem Ort nach Nullen zu suchen, an dem ein Nullzeiger gegen eine Vorbedingung verstößt, ist für mich völliger Wahnsinn, es sei denn, Ihre Software ist so kritisch gegen Assertionsfehler und Produktionsabstürze, dass das Potenzial dieses Szenarios vorzuziehen ist.

Ist es für einen Codierungsstandard sinnvoll, zu verlangen, dass jeder einzelne in einer Funktion dereferenzierte Zeiger zuerst auf NULL überprüft wird - auch auf private Datenelemente?

Also würde ich sagen, absolut nicht. Es ist nicht einmal "sicher". Es kann durchaus das Gegenteil sein und alle Arten von Fehlern in Ihrer Codebasis maskieren, die im Laufe der Jahre zu den schrecklichsten Szenarien führen können.

assert ist der Weg hierher. Verstöße gegen die Voraussetzungen sollten nicht unbemerkt bleiben, da sonst Murphys Gesetz leicht in Kraft treten kann.

3
user204677

Objective-C behandelt beispielsweise jeden Methodenaufruf für ein nil -Objekt als No-Op, das einen Nullwert ergibt. Diese Entwurfsentscheidung in Objective-C bietet aus den in Ihrer Frage vorgeschlagenen Gründen einige Vorteile. Das theoretische Konzept, jeden Methodenaufruf auf Null zu setzen, hat einige Vorteile, wenn es gut bekannt gemacht und konsequent angewendet wird.

Der Code lebt jedoch in einem Ökosystem, nicht in einem Vakuum. Das nullgeschützte Verhalten wäre in C++ nicht idiomatisch und überraschend und sollte daher als schädlich angesehen werden. Zusammenfassend lässt sich sagen, dass niemand C++ - Code so schreibt, also nicht ! Beachten Sie jedoch als Gegenbeispiel, dass das Aufrufen von free() oder delete für ein NULL in C und C++ garantiert ein No-Op ist.


In Ihrem Beispiel wäre es wahrscheinlich sinnvoll, eine Behauptung im Konstruktor zu platzieren, dass msgSender nicht null ist. Wenn der Konstruktor eine Methode aufruft auf msgSender sofort, dann wäre eine solche Behauptung nicht notwendig, da sie sowieso genau dort abstürzen würde. Da es sich jedoch lediglich um SpeichernmsgSender für die zukünftige Verwendung handelt, ist es nicht offensichtlich, wenn man sich eine Stapelspur von SignalShutdown() ansieht, wie der Wert zustande gekommen ist be NULL, daher würde eine Zusicherung im Konstruktor das Debuggen erheblich vereinfachen.

Noch besser ist, dass der Konstruktor ein const IMsgSender& Referenz, die unmöglich NULL sein kann.

2
200_success

Die Verwendung eines Zeigers anstelle einer Referenz würde mir sagen, dass msgSender ist nur eine Option und hier wäre die Nullprüfung richtig. Das Code-Snippet ist zu langsam, um dies zu entscheiden. Vielleicht gibt es andere Elemente in PowerManager, die wertvoll (oder testbar) sind ...

Bei der Wahl zwischen Zeiger und Referenz wäge ich beide Optionen gründlich ab. Wenn ich einen Zeiger für ein Mitglied verwenden muss (auch für private Mitglieder), muss ich die Prozedur if (x) jedes Mal akzeptieren, wenn ich sie dereferenziere.

1
Wolf

Der Grund, warum Sie aufgefordert werden, Null-Dereferenzen zu vermeiden, besteht darin, sicherzustellen, dass Ihr Code robust ist. Beispiele für Junior-Programmierer vor langer, langer Zeit sind nur Beispiele. Jeder kann den Code versehentlich brechen und eine Null-Dereferenzierung verursachen - insbesondere für Globals und Klassenglobals. In C und C++ ist dies mit der direkten Speicherverwaltung noch häufiger möglich. Sie werden vielleicht überrascht sein, aber so etwas passiert sehr oft. Selbst von sehr sachkundigen, sehr erfahrenen und sehr erfahrenen Entwicklern.

Sie müssen nicht alles auf Null setzen, aber Sie müssen sich vor Dereferenzen schützen, bei denen die Wahrscheinlichkeit, dass sie Null sind, angemessen ist. Dies ist häufig der Fall, wenn sie in verschiedenen Funktionen zugewiesen, verwendet und dereferenziert werden. Es ist möglich, dass eine der anderen Funktionen geändert wird und Ihre Funktion beeinträchtigt. Es ist auch möglich, dass eine der anderen Funktionen nicht in der richtigen Reihenfolge aufgerufen wird (z. B. wenn Sie einen Deallocator haben, der separat vom Destruktor aufgerufen werden kann).

Ich bevorzuge den Ansatz, den Ihre Mitarbeiter Ihnen in Kombination mit der Verwendung von assert mitteilen. Absturz in der Testumgebung, sodass es offensichtlicher ist, dass ein Problem behoben werden muss und in der Produktion ordnungsgemäß fehlschlägt.

Sie sollten auch ein robustes Tool zur Codekorrektur wie Coverity oder Fortify verwenden. Und Sie sollten alle Compiler-Warnungen adressieren.

Bearbeiten: Wie andere bereits erwähnt haben, ist ein stillschweigendes Versagen, wie in einigen Codebeispielen, im Allgemeinen auch das Falsche. Wenn Ihre Funktion den Wert null nicht wiederherstellen kann, sollte sie einen Fehler zurückgeben (oder eine Ausnahme auslösen). Der Anrufer ist dafür verantwortlich, entweder seine Anrufreihenfolge zu korrigieren, einen Fehler wiederherzustellen oder an seinen Anrufer zurückzugeben (oder eine Ausnahme auszulösen) und so weiter. Schließlich kann eine Funktion entweder ordnungsgemäß wiederherstellen und fortfahren, ordnungsgemäß wiederherstellen und fehlschlagen (z. B. wenn eine Datenbank eine Transaktion aufgrund eines internen Fehlers für einen Benutzer fehlschlägt, aber nicht akut beendet wird), oder die Funktion stellt fest, dass der Anwendungsstatus beschädigt ist und nicht behebbar und die Anwendung wird beendet.

1
atk

Es hängt davon ab, was passieren soll.

Sie haben geschrieben, dass Sie an "einem Unterhaltungselektronikgerät" arbeiten. Wenn irgendwie ein Fehler durch Setzen von msgSender_ bis NULL, willst du

  • das Gerät, um fortzufahren, SignalShutdown zu überspringen, aber den Rest seines Betriebs fortzusetzen, oder
  • das Gerät zum Absturz zu bringen und den Benutzer zum Neustart zu zwingen?

Abhängig von der Auswirkung des nicht gesendeten Abschaltsignals kann Option 1 eine praktikable Wahl sein. Wenn der Benutzer weiterhin seine Musik hören kann, das Display jedoch weiterhin den Titel des vorherigen Titels anzeigt, ist möglicherweise einem vollständigen Absturz von vorzuziehen das Gerät.

Wenn Sie Option 1 wählen, ist natürlich ein assert (wie von anderen empfohlen) wichtig , um die Wahrscheinlichkeit eines solchen Fehlers zu verringern während der Entwicklung unbemerkt einschleichen. Der Nullschutz if dient nur zur Fehlerminderung in der Produktion.

Persönlich bevorzuge ich auch den "Crash Early" -Ansatz für Produktions-Builds, aber ich entwickle Unternehmenssoftware, die im Fehlerfall leicht repariert und aktualisiert werden kann. Für Geräte der Unterhaltungselektronik ist dies möglicherweise nicht so einfach.

0
Heinzi