Frage

Ich habe gehört, Sie nie einen String werfen sollte, weil es einen Mangel an Informationen ist, und Sie werden Ausnahmen fangen Sie nicht erwarten, zu fangen. Was ist gute Praxis Ausnahmen zu werfen? Haben Sie eine Basisausnahmeklasse erben? Haben Sie viele Ausnahmen oder wenige haben? tun Sie MyExceptionClass & oder const MyExceptionClass & usw. Auch wissen sollte ich Ausnahmen nie in Destruktoren geworfen worden

ich werde hinzufügen, dass ich Design verstehen vertraglich und wenn Ausnahme zu werfen. Ich frage, wie ich sollte Ausnahmen auslösen.

War es hilfreich?

Lösung

Meiner Meinung nach sollte eine Funktion eine Ausnahme aus, wenn es nicht sein „Versprechen“ halten kann, wenn es zu brechen hat seinen „Vertrag“. Die Funktion der Signatur (Name und Parameter) bestimmt seinen Vertrag.

Vor dem Hintergrund dieser beiden Member-Funktionen:

const Apple* FindApple(const wchar_t* name) const;
const Apple& GetApple(const wchar_t* name) const;

Die Namen dieser Funktionen sowie deren Rückgabewerte an mir zeigen, dass im Falle von FindApple die Funktion ist durchaus in der Lage NULL zurückzugeben, wenn der richtige Apfel nicht gefunden wurde, aber im Fall von GetApple Sie erwarten ein Apfel zurückzukehren. Wenn die zweite Funktion nicht ihr Versprechen halten kann, muss es eine Ausnahme aus.

Ausnahmen sind für die außergewöhnlichen Bedingungen gemeint, in denen eine Funktion der Berichterstattung diese Bedingungen keine andere Möglichkeit hat. Wenn Sie es einen Teil der Versprechen zu machen (sprich: Funktion Unterschrift). Dann kann es diese Bedingung melden, ohne eine Ausnahme zu werfen

Beachten Sie, dass im Fall von FindApple , es ist bis zu dem Anrufer zu entscheiden, wie die Bedingung zu handhaben „nicht den richtigen Apfel zu finden“, weil es nicht mehr ein außergewöhnlich guten Zustand.

Sie könnten versucht sein, zu versuchen, alle Ausnahmen zu vermeiden, aber das bedeutet, dass Sie für alle möglichen Ausnahmebedingungen zu berücksichtigen haben, und Sie die Belastung für den Anrufer stattdessen platzieren. Der Anrufer muss für „Fehlerbedingungen“ überprüfen, dann.

Schließlich muss eine Ausnahme behandelt werden, sondern nur durch den Anrufer, dass weiß, wie eine bestimmte Bedingung in einer sinnvollen Weise zu handhaben . Und ich meine das im weitesten Interpretation: ein Dienst, der wieder versuchen, später aufgibt, eine Benutzeroberfläche, die eine hilfreiche Fehlermeldung liefert, eine Web-Anwendung, die ein „oops“ -Bildschirm zeigt aber, dass erholt sich gut, ... und so weiter .

Dave

Andere Tipps

Eine grundlegende Sache ist nur Ausnahmen für Ausnahmesituationen zu reservieren. Verwenden Sie sie nicht für die Ablaufsteuerung. Zum Beispiel: „Datei nicht gefunden“ sollte nicht eine Ausnahme sein, sollte es ein Fehlercode oder Rückgabewert sein (es sei denn, die Datei ist etwas, das muss existieren, beispielsweise eine Konfigurationsdatei). Aber wenn eine Datei verschwindet plötzlich während Sie es verarbeiten, dann eine Ausnahme zu werfen ist eine gute Wahl.

Wenn Ausnahmen sparsam verwendet werden, brauchen Sie nicht, Ihren Code in einen Try-Catch -spaghetti zu drehen, um zu vermeiden Aufnahme unverständlich-in-the-Kontext Ausnahmen von den tieferen Schichten.

Mit dem Standard Ausnahmen! Wenn Sie einen bestimmten Fehler, versuchen Sie es mit Rückgabewert zu vermeiden. Wenn Sie Haben Ausnahmen verwenden, definieren Sie Ihre individuelle Ausnahme, die von Exception erbt und eine benutzerdefinierte Nachricht erstellen.

Manchmal kann es vorkommen, dass Sie nicht in der Lage sind Fehlercode zB zurückzukehren. wenn Sie benötigen genauen Zusammenhang, wenn die Fehlersituation aufgetreten, zB. wenn Sie benötigen auf Fehlerstatus 3 Ebene propagieren -. Sie losen Kontext

In dieser Situation benutzerdefinierten Klasse ist die beste Lösung. Ich benutze diesen Ansatz, meine eigenen Inline-Klassen definieren (es gibt keine CPP für sie, nur .h) zB:.

class DeviceException {
    ;
}

class DeviceIOException: public DeviceException {
    DeviceIOException(std::string msg, int errorCode);
}

etc.

Ich kann dann beurteilen / act auf der Ausnahme nach Art und darin enthaltenen Informationen.

Ich habe immer eine Ausnahme mit einer Meldung werfen, wo es aufgetreten ist und was verursacht es geschehen:

throw NException("Foo::Bar", "Mungulator cause a stack overflow!");

Sie können dann diese Strings in Message usw. verwendet werden.

Ich fange immer über

catch (NException& ex) { ... }

Wenn Sie Windows ausgeführt wird, können Sie den Fehlerwert übergeben und haben eine Funktion ableiten die Fehlermeldung. Das beste Beispiel hierfür ist in Windows über C / C ++ von Jeffrey Richter .

Zeiger Werfen ist wahrscheinlich nicht eine gute Sache, da es Eigentum des geworfenen Objekts erschwert. Klassentyp Ausnahmen sind wahrscheinlich besser als Grundlagen, nur weil sie mehr Informationen über den Grund für die Ausnahme enthalten können.

eine Klasse oder Klassenhierarchie gibt es ein paar Punkte Bei der Verwendung sollten Sie berücksichtigen:

  1. Sowohl der Kopierkonstruktor und destructor des Ausnahmeobjekts darf auf keinen Fall eine Ausnahme werfen. Wenn sie tun, sind Sie Programm wird mit sofortiger Wirkung kündigen. (ISO 15,5 / 1)

  2. Wenn Sie Ihre Ausnahme-Objekte haben Grund Klassen, dann öffentliche Vererbung verwenden.
    Ein Handler wird nur für eine ausgewählt werden wenn die Basis an Basisklasse abgeleitet Klasse ist zugänglich . (ISO 15,3 / 3)

  3. Schließlich (für alle Ausnahmetypen) gewährleisten, dass der Ausdruck geworfen werden kann nicht selbst in einer Ausnahme führt geworfen.

Zum Beispiel:

class Ex {
public:
  Ex(int i) 
  : m_i (i)
  {
    if (i > 10) {
      throw "Exception value out of range";
    }
  }

  int m_i;
};


void foo (bool b) {
  if (! b) {
     // 'b' is false this is bad - throw an exception
     throw Ex(20);    // Ooops - throw's a string, not an Ex
  }
}

Sie sollten immer eine Ausnahmeklasse werfen von std :: exception abgeleitet. Dies ermöglicht eine gewisse Konsistenz Ihre Oberfläche und mehr Flexibilität für die Kunden dieser Methoden oder Funktionen ermöglicht. Zum Beispiel, wenn Sie einen Haken alle Handler hinzufügen Sie in der Lage sein kann, ein

catch(std::exception& e)
Block hinzufügen und mit ihr geschehen. (Obwohl oft werden Sie nicht in der Lage sein, mit dem wegzukommen, wenn Sie alle den Code nicht steuern, die werfen kann).

Ich neige dazu, nur Ausnahmen von der Standard vorgesehen werfen (das heißt std :: runtime_error), aber wenn Sie zusätzliche Granularität Ihre Handler zur Verfügung stellen möchten, sollten Sie fühlen sich frei, Ihre eigenen von std :: exception abzuleiten. Siehe die C ++ FAQ Lite .

Außerdem sollten Sie einen temporären werfen und sie durch Bezugnahme fangen (die Kopie Ctor zu vermeiden, auf Ihrer Fang-Website aufgerufen werden). Werfen Zeiger ist auch verpönt, da es ist unklar, wer den Speicher aufräumen sollte. C ++ FAQ Lite behandelt das auch.

Für ein aktuelles Projekt, dachten wir über die entsprechende Aktion, die von der Hauptprogrammschleife genommen werden konnte. Das Basisprogramm akzeptiert XML-Nachrichten und speichert die Informationen in eine Datenbank (mit einer angemessenen Menge an Verarbeitungs dazwischen).

  1. Datenfehler, die etwas falsch die Eingabe an. Geeignete Maßnahmen sind es, die Nachricht in ein Log-Verzeichnis zu speichern, aber es nicht verarbeiten.
  2. Infrastruktur Fehler, die einige Subkomponenten zeigen (wie die Eingangswarteschlange, eine SQL-Datenbank, eine JNI-Bibliothek) funktioniert nicht richtig. Schlaf für ein paar Minuten wieder an.
  3. Konfigurationsfehler, die ein Aspekt Konfiguration ist nicht praktikabel anzuzeigen. Beenden Sie das Programm.

Der erste Punkt ist eine geprüfte Ausnahme, da wir Datenprüfung als Teil der Schnittstelle einer Methode zu sein. Die anderen sind nicht markiert, da die Hauptschleife nicht die Implementierungen von Subkomponenten wissen können, beispielsweise eine Implementierung kann eine SQL-Datenbank verwenden, oder kann einfach Daten im Speicher bestehen bleiben -. die Anrufer nicht wissen muss,

Wenn Sie Ausnahmen von einer anderen Komponente Entwickler werfen wird Downstream verwenden möchten, gehen Sie bitte ihnen einen großen Gefallen und immer leiten Sie Ihre eigene Exception-Klassen (wenn Sie sie wirklich brauchen, um die Standard-Ausnahmen C.F verwenden) von std :: exception. Vermeiden Sie unter allen Umständen völlige Abscheulichkeiten wie das Werfen Ints, HRESULTS, char *, std :: string ...

Wie gesagt war sie bereits verwendet für Ausnahmesituationen nur.

bietet immer eine Möglichkeit für den Benutzer, eine Ausnahme zu vermeiden, werfen, zum Beispiel. wenn Sie die Methode haben, das wird ausgelöst, wenn so etwas wie dies schief geht:

public void DoSomethingWithFile() {
    if(!File.Exists(..))
        throw new FileNotFoundException();
}

Geben Sie eine andere Methode für den Benutzer zu nennen:

public bool CanDoSomething() {
    return File.Exists(..);
}

Auf diese Weise gibt der Anrufer kann Ausnahmen vermeiden, wenn er will. Zögern Sie nicht, zu werfen, wenn etwas falsch ist -. „fail schnell“, aber immer Ausnahme freier Pfad angeben

Halten Sie auch Ihre Ausnahmeklasse Hierarchie flach und einen Blick auf den Standard-Ausnahmen wie InvalidStateException und ArgumentNullExcpetion nehmen.

Hier ist ein einfaches Beispiel, eine Ausnahme zu werfen, die kaum alle Ressourcen nehmen:

class DivisionError {};
class Division
{
public:
    float Divide(float x, float y) throw(DivisionError)
    {
        float result = 0;
        if(y != 0)
            result = x/y;
        else
            throw DivisionError();
        return result;
    }
};

int main()
{
    Division d;
    try
    {
        d.Divide(10,0);
    }
    catch(DivisionError)
    {
        /*...error handling...*/
    }
}

Die leere Klasse, die ausgelöst wird übernimmt keine Ressource oder nur sehr wenige ...

Von der C ++ FAQ [17.12] Was soll ich werfe ? :

  

Im Allgemeinen ist es am besten Objekte zu werfen, nicht Einbauten.   Wenn möglich, sollten Sie Instanzen von Klassen werfen, dass   ableiten (letztlich) von der std::exception Klasse.

... und

  

Die am weitesten verbreitete Praxis ist eine vorübergehende zu werfen:    (siehe Beispiel, das folgt)

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