In C ++, was sind die Vorteile von Ausnahmen und versuchen Sie / fangen, anstatt nur einen Fehlercode zurückkehrt?

StackOverflow https://stackoverflow.com/questions/196522

Frage

Ich habe programmiert C und C ++ für eine lange Zeit und bis jetzt habe ich noch nie Ausnahmen verwendet und try / catch. Was sind die Vorteile, dass anstelle von nur Rückgabecodes Fehlerfunktionen zu haben?

War es hilfreich?

Lösung

Möglicherweise ein offensichtlicher Punkt - kann ein Entwickler ignorieren (oder nicht bewusst) Ihren Rückgabestatus und geht völlig ahnungslos, dass etwas fehlgeschlagen

.

muss eine Ausnahme in irgendeiner Weise anerkannt werden - es kann nicht stillschweigend, ohne aktiv etwas dafür zu schaffen außer Acht gelassen werden, dies zu tun

.

Andere Tipps

Der Vorteil von Ausnahmen sind zweifach:

  • Sie können nicht ignoriert werden. Sie müssen auf einer bestimmten Ebene mit ihnen umgehen, oder sie werden Ihr Programm beenden. Mit dem Fehlercode, müssen Sie explizit für sie überprüfen, oder sie verloren sind.

  • Sie können ignoriert werden. Wenn ein Fehler nicht mit auf einer Ebene behandelt werden können, wird es automatisch Blase auf die nächste Ebene, wo es sein kann. Fehlercodes müssen explizit übergeben werden, bis sie das Niveau erreichen, wo es behandelt werden kann.

Der Vorteil ist, dass Sie nicht haben, um den Fehlercode nach jedem potenziell andernfalls Anruf zu überprüfen. Damit dies jedoch funktioniert, müssen Sie es mit RAII-Klassen kombinieren, so dass alles auf, als der Stapel abwickelt automatisch gereinigt wird.

Mit Fehlermeldungen:

int DoSomeThings()
{
    int error = 0;
    HandleA hA;
    error = CreateAObject(&ha);
    if (error)
       goto cleanUpFailedA;

    HandleB hB;
    error = CreateBObjectWithA(hA, &hB);
    if (error)
       goto cleanUpFailedB;

    HandleC hC;
    error = CreateCObjectWithA(hB, &hC);
    if (error)
       goto cleanUpFailedC;

    ...

    cleanUpFailedC:
       DeleteCObject(hC);
    cleanUpFailedB:
       DeleteBObject(hB);
    cleanUpFailedA:
       DeleteAObject(hA);

    return error;
}

Mit Ausnahmen und RAII

void DoSomeThings()
{
    RAIIHandleA hA = CreateAObject();
    RAIIHandleB hB = CreateBObjectWithA(hA);
    RAIIHandleC hC = CreateCObjectWithB(hB);
    ...
}

struct RAIIHandleA
{
    HandleA Handle;
    RAIIHandleA(HandleA handle) : Handle(handle) {}
    ~RAIIHandleA() { DeleteAObject(Handle); }
}
...

Auf den ersten Blick die RAH / Exceptions Version scheint länger, bis Sie erkennen, dass der Bereinigungscode geschrieben werden muss nur einmal (und es gibt Möglichkeiten, dies zu vereinfachen). Aber die zweite Version von DoSomeThings ist viel klarer und wartbar.

Versuchen Sie nicht, und verwenden Sie Ausnahmen in C ++ ohne RAII Idiom, wie Sie Ressourcen und Speicher undicht wird. Alle Ihre Bereinigung muss in Destruktoren von Stapel zugewiesenen Objekte durchgeführt werden.

Ich weiß, es gibt auch andere Möglichkeiten, um den Fehlercode Handhabung zu tun, aber sie alle etwas das gleiche am Ende der Suche. Wenn Sie die gotos fallen, erhalten Sie aufzuräumen Code Wiederholung auf.

Ein Punkt für Fehlercodes, ist, dass sie deutlich zu machen, wo die Dinge fehlschlagen können, und wie sie ausfallen können. In dem obigen Code, schreiben Sie es mit der Annahme, dass die Dinge nicht scheitern werden (aber wenn sie es tun, werden Sie durch den RAH-Wrapper geschützt werden). Aber Sie am Ende zahlen weniger Beachtung, wo die Dinge schief gehen können.

Die Ausnahmebehandlung ist nützlich, weil es macht es einfach geschrieben, um die Fehlerbehandlung Code aus dem Code zu trennen, die Funktion des Programms zu behandeln. Dies macht das Lesen und Schreiben des Codes zu erleichtern.

Neben den anderen Dingen, die erwähnt wurden, können Sie nicht einen Fehlercode von einem Konstruktor zurück. Destructors entweder, aber Sie sollten eine Ausnahme von einem Destruktor vermeiden werfen.

  • Rückkehr einen Fehlercode, wenn ein Fehlerzustand ist erwartet in einigen Fällen
  • eine Ausnahme aus, wenn ein Fehlerzustand ist nicht in jedem Fall erwartet

Im ersten Fall der Aufrufer der Funktion müssen Sie den Fehlercode für den erwarteten Ausfall überprüfen; im letzteren Fall kann die Ausnahme von jedem Anrufer bis den Stapel (oder die Standard-Handler) behandelt werden, wie angemessen ist,

Ich schrieb einen Blog-Eintrag über diese ( Ausnahmen machen für elegant-Code ), die anschließend in Überlastungs veröffentlicht wurde. Ich schrieb tatsächlich diese als Antwort auf etwas, sagte Joel auf der Podcast-Stackoverflow!

Wie auch immer, ich bin der festen Überzeugung, dass Ausnahmen sind vorzuziehen Codes in den meisten Fällen auf Fehler. Ich finde es wirklich schmerzhaft Funktionen zu verwenden, die Fehlercodes zurück: Sie haben den Fehlercode nach jedem Aufruf zu überprüfen, die den Fluss des anrufenden Code stören können. Es bedeutet auch, können Sie nicht überladene Operatoren verwenden, da es keine Möglichkeit gibt, den Fehler zu signalisieren.

Der Schmerz Fehlercodes der Überprüfung bedeutet, dass die Menschen oft vernachlässigt, dies zu tun, so dass sie völlig sinnlos machen: zumindest müssen Sie explizit Ausnahmen mit einer catch Anweisung ignorieren

.

Die Verwendung von Destruktoren in C ++ und Entsorger in .NET, um sicherzustellen, dass die Ressourcen richtig in Gegenwart von Ausnahmen befreit sind, kann auch stark Code vereinfachen. Um das gleiche Maß an Schutz mit Fehlercodes zu erhalten, müssen Sie entweder eine Menge if Aussagen, viele duplizierte Bereinigungscode oder goto Anrufe zu einem gemeinsamen Block der Bereinigung am Ende einer Funktion. Keine dieser Optionen sind angenehm.

Hier eine gute Erklärung von EAFP ( "Leichter um Vergebung zu bitten als Permission ".), die ich denke, hier gilt auch, wenn es sich um eine Python-Seite in Wikipedia ist. Mit führt Ausnahmen zu einer natürlicheren Art der Codierung, IMO -. Und nach der Meinung von vielen anderen, auch

Als ich noch C ++, unsere Standard-Erklärung zu lehren, war, dass sie erlaubt Ihnen sonnige Tage und regnerischen Tag Szenarien zu vermeiden Kabelgewirr. Mit anderen Worten, Sie könnten eine Funktion als schreiben, wenn alles in Ordnung funktionieren würde, und die Ausnahme am Ende fangen.

Ohne Ausnahme, würden Sie einen Rückgabewert von jedem Anruf erhalten müssen und sicherzustellen, dass es immer noch legitim ist.

Ein verwandtes Nutzen, ist natürlich, dass Sie nicht „Abfall“ Ihren Rückgabewert auf Ausnahmen (und damit Methoden erlauben, die Lücke sollte nichtig), und können auch Fehler von Konstruktoren und Destruktoren zurück.

Googles C ++ Style Guide eine große hat, gründlich Analyse der Vor- und Nachteile der Ausnahme Verwendung in C ++ Code. Es zeigt auch einige der größeren Fragen, die Sie stellen sollten; das heißt zu tun beabsichtige ich meinen Code an andere zu verteilen?

(die mit einer Ausnahme-fähige Schwierigkeit der Integration Codebasis haben können)

Manchmal hat man wirklich eine Ausnahme, um Flagge zu verwenden, um einen Ausnahmefall. Zum Beispiel, wenn etwas geht in einem Konstruktor falsch, und Sie finden es sinnvoll ist, den Anrufer darüber zu informieren, dann haben Sie keine andere Wahl, als eine Ausnahme zu werfen.

Ein weiteres Beispiel: Manchmal gibt es keinen Wert Ihre Funktion zurückgeben kann, einen Fehler zu bezeichnen; jeder Wert der Funktion zurückgeben bezeichnet Erfolg.

int divide(int a, int b)
{
    if( b == 0 )
        // then what?  no integer can be used for an error flag!
    else
        return a / b;
}

Die Tatsache, dass Sie Ausnahmen bestätigen müssen, ist richtig, aber dies auch Fehler structs implementiert werden kann. Sie könnten eine Basisfehlerklasse erstellen, die in seiner dtor überprüft, ob eine bestimmte Methode (z ISOK) aufgerufen wurde. Wenn nicht, könnten Sie etwas anmelden und dann beenden, oder eine Ausnahme auslösen, oder eine Assertion erhöhen, etc ...

Aufruf einfach die ISOK auf dem Fehlerobjekt ohne darauf zu reagieren, wäre dann die äquivalente Fang des Schreibens (...) {} Beide Aussage würde den gleichen Mangel an Programmierern guten Willen zeigen.

Der Transport des Fehlercodes bis zu dem richtigen Niveau ist eine größere Sorge. Sie müssten im Grunde fast alle Methoden machen zurückgeben einen Fehlercode aus dem alleinigen Grund der Ausbreitung. Aber dann wieder, eine Funktion oder Methode sollte immer mit den Ausnahmen, mit Anmerkungen versehen wird, erzeugen kann. Also im Grunde Sie gleiche Problem haben, ohne eine Schnittstelle zu unterstützen.

Wie @ Martin wirft Ausnahmen wies darauf hin, zwingt den Programmierer den Fehler zu behandeln. Zum Beispiel ist Return-Codes nicht überprüft eine der größten Quellen von Sicherheitslücken in C-Programmen. Ausnahmen stellen Sie sicher, dass Sie den Fehler behandeln (hoffentlich) und eine Art bieten den Weg für Ihr Programm erholen. Und wenn Sie eine Ausnahme zu ignorieren, anstatt ein Sicherheitsloch einführen Ihr Programm stürzt ab.

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