Frage

In C ++ können Sie festlegen, dass eine Funktion oder eine Ausnahme nicht durch die Verwendung einer Ausnahme-Spezifizierer werfen kann. Zum Beispiel:

void foo() throw(); // guaranteed not to throw an exception
void bar() throw(int); // may throw an exception of type int
void baz() throw(...); // may throw an exception of some unspecified type

Ich bin zweifelhaft über die Verwendung von ihnen tatsächlich aus folgendem Grunde:

  1. Der Compiler nicht wirklich Ausnahme Bezeich in jedem rigoros durchzusetzen, so dass die Vorteile sind nicht groß. Im Idealfall würden Sie gerne einen Compiler-Fehler erhalten.
  2. Wenn eine Funktion eine Ausnahme-Spezifizierer verletzt, ich denke, das Standardverhalten ist, das Programm zu beenden.
  3. In VS.Net behandelt es throw (X) als throw (...), so Einhaltung der Norm ist nicht stark.

Glauben Sie, Ausnahme Bezeich verwendet werden sollte?
Bitte antworten Sie mit „Ja“ oder „Nein“ und einige Gründe liefern, um Ihre Antwort zu rechtfertigen.

War es hilfreich?

Lösung

Nein.

Hier sind einige Beispiele, warum:

  1. Template-Code ist unmöglich, mit Ausnahme Spezifikationen zu schreiben,

    template<class T>
    void f( T k )
    {
         T x( k );
         x.x();
    }
    

    Die Kopien könnten werfen, könnten die Parameterübergabe werfen, und x() könnte einige unbekannte Ausnahme aus.

  2. Exception-Spezifikationen sind in der Regel Dehnbarkeit zu verbieten.

    virtual void open() throw( FileNotFound );
    

    könnte entwickeln sich zu

    virtual void open() throw( FileNotFound, SocketNotReady, InterprocessObjectNotImplemented, HardwareUnresponsive );
    

    Sie könnte wirklich schreiben, wie

    throw( ... )
    

    Die erste ist nicht erweiterbar, die zweite ist zu ehrgeizig und die dritte ist wirklich, was Sie meinen, wenn Sie virtuelle Funktionen schreiben.

  3. Legacy-Code

    Wenn Sie Code schreiben, die auf einer anderen Bibliothek angewiesen ist, Sie wissen nicht wirklich, was es tun könnte, wenn etwas schief geht.

    int lib_f();
    
    void g() throw( k_too_small_exception )
    { 
       int k = lib_f();
       if( k < 0 ) throw k_too_small_exception();
    }
    

    g wird beendet, wenn lib_f() wirft. Dies ist (in den meisten Fällen) nicht das, was Sie wirklich wollen. std::terminate() sollte nie aufgerufen werden. Es ist immer besser, die zum Absturz der Anwendung mit einer nicht behandelten Ausnahme zu lassen, von dem man einen Stapel-Trace abrufen kann, als zu leise / heftig sterben.

  4. Schreiben Sie Code, häufige Fehler zurückgibt und wirft auf außergewöhnliche Gelegenheiten.

    Error e = open( "bla.txt" );
    if( e == FileNotFound )
        MessageUser( "File bla.txt not found" );
    if( e == AccessDenied )
        MessageUser( "Failed to open bla.txt, because we don't have read rights ..." );
    if( e != Success )
        MessageUser( "Failed due to some other error, error code = " + itoa( e ) );
    
    try
    {
       std::vector<TObj> k( 1000 );
       // ...
    }
    catch( const bad_alloc& b )
    { 
       MessageUser( "out of memory, exiting process" );
       throw;
    }
    

Dennoch, wenn Ihre Bibliothek nur Ihre eigenen Ausnahmen auslöst, können Sie Ausnahme-Spezifikationen verwenden, um Ihre Absicht zu erklären.

Andere Tipps

Vermeiden Ausnahme Spezifikationen in C ++. Die Gründe, die Sie in Ihrer Frage geben, sind ein ziemlich guter Anfang dafür, warum.

Siehe Herb Sutter "Ein pragmatischer Blick auf Exception-Spezifikationen" .

Ich denke, die standardmässig mit Ausnahme Konvention (für C ++)
Ausnahme Bezeich war ein Experiment in der C ++ Standard, meist gescheitert.
Die Ausnahme ist, dass der keine throw Spezifizierer nützlich ist, aber Sie sollten auch den entsprechenden try catch-Block intern in dem der Code müssen Sie die Spezifikationsübereinstimmt. Herb Sutter hat eine Seite zum Thema. Gotch 82

In einem Zusatz ich denke, es lohnt sich Exception Garantien zu beschreiben.

Diese sind im Allgemeinen Dokumentation darüber, wie der Zustand eines Objekts durch Ausnahmen betroffen ist eine Methode für das Objekt zu entkommen. Leider erzwungen oder sonst werden sie nicht vom Compiler erwähnt.
Boost und Ausnahmen

Ausnahme Garantien

Keine Garantie:

  

Es gibt keine Garantie über den Zustand des Objekts nach einer Ausnahme entkommt ein Verfahren
     In diesen Situationen sollte das Objekt nicht mehr verwendet werden.

Grund Garantie:

  

In fast allen Situationen soll dies die Mindestgarantie sein ein Verfahren zur Verfügung stellt.
     Dies garantiert den Zustand des Objekts gut definiert ist und nach wie vor konsequent genutzt werden kann.

Starke Garantie: (aka Transactional-Garantie)

  

Damit ist gewährleistet, dass das Verfahren erfolgreich abgeschlossen werden
     Oder eine Ausnahme ausgelöst werden und die Objekte Zustand wird sich nicht ändern.

Keine Wurf Garantie:

  

Das Verfahren gewährleistet, dass keine Ausnahmen erlaubt aus dem Verfahren zu propagieren.
     Alle Destruktoren sollten diese Garantie machen.
     | N. B. Wenn eine Ausnahme ein destructor entkommt, während eine Ausnahme bereits ausbreitet
     | die Anwendung beenden

gcc werden Warnungen ausgeben, wenn Sie Ausnahme-Spezifikationen verstoßen. Was ich tue, ist, Makros zu verwenden, um die Ausnahme Spezifikationen zu verwenden, nur in einem „Fussel“ Modus kompilieren ausdrücklich für die Überprüfung der Ausnahme stimmt mit meiner Dokumentation, um sicherzustellen.

Die einzige nützliche Ausnahme Spezifizierer "throw ()", wie in "nicht werfen".

Nein. Wenn Sie sie verwenden und eine Ausnahme ausgelöst wird, dass Sie nicht angegeben haben, entweder von Ihrem Code oder Code von Code aufgerufen, dann ist das Standardverhalten umgehend Ihr Programm zu beenden.

Auch ich glaube, ihre Verwendung in aktuellen Entwürfen des C ++ 0x-Standard veraltet.

Ausnahme Spezifikationen sind nicht wunderbar nützliche Tools in C ++. Allerdings gibt / ist / eine gute Verwendung für sie, wenn sie mit std :: kombiniert unerwartet.

Was ich in einigen Projekten zu tun ist Code mit Ausnahme Spezifikationen und dann set_unexpected call () mit einer Funktion, die eine besondere Ausnahme von meinem eigenen Design werfen. Diese Ausnahme, bei der Konstruktion, wird eine Rückverfolgung (in einer plattformspezifisch) und wird abgeleitet von std :: bad_exception (damit es vermehrt werden, wenn gewünscht). Wenn es eine terminate () Anruf verursacht, wie es in der Regel der Fall ist, wird der Backtrace durch das, was gedruckt () (sowie die ursprüngliche Ausnahme, die es verursacht, nicht zu schwer, das zu finden) und so erhalte ich Informationen, wo mein Auftrag war verletzt, wie, was unerwartete Bibliothek Ausnahme ausgelöst wurde.

Wenn ich das tue, habe ich nie Ausbreitung der Bibliothek Ausnahmen (außer std sind) erlauben und leiten alle meine Ausnahmen von std :: exception. Wenn eine Bibliothek zu werfen entscheidet, werde ich fangen und wandle in meine eigene Hierarchie, so dass für mich immer um den Code zu steuern. Templated Funktionen, die abhängige Funktionen aufrufen sollten Exception-Spezifikationen aus offensichtlichen Gründen vermeiden; aber es ist selten, dass eine Templat-Funktion Schnittstelle mit Bibliothek Code hat sowieso (und einige Bibliotheken wirklich Vorlagen in nützlicher Weise verwendet werden).

Wenn Sie Code schreiben, die von Menschen verwendet werden, die eher in der Funktionsdeklaration als alle Kommentare um es aussehen würde, dann eine Spezifikation wird ihnen sagen, welche Ausnahmen sie könnten fangen wollen.

Ansonsten finde ich es nicht besonders nützlich, alles andere als throw() zu verwenden, um anzuzeigen, dass es keine Ausnahmen wirft.

A „throw ()“ Spezifikation ermöglicht es den Compiler einige Optimierungen durchzuführen, wenn Code-Flow-Analyse zu tun, wenn es diese Funktion weiß nie eine Ausnahme (oder zumindest verspricht, nie eine Ausnahme auslösen) werfen. Larry Osterman spricht über diese hier kurz:

http://blogs.msdn.com/larryosterman /archive/2006/03/22/558390.aspx

Generell würde ich nicht Ausnahme Bezeich verwenden. Jedoch in Fällen, in denen, wenn eine anderen Ausnahme von der Funktion in Frage kommen sollten, dass das Programm endgültig nicht in der Lage wäre, zu richtig , dann kann es nützlich sein. In allen Fällen stellen Sie sicher, klar zu dokumentieren, was Ausnahmen von dieser Funktion zu erwarten.

Ja, das erwartete Verhalten eines nicht spezifizierten Ausnahme von einer Funktion mit Ausnahme Bezeich geworfen ist beendet () aufrufen.

Ich werde auch beachten Sie, dass Scott Meyers befasst sich mit diesem Thema in effektiver C ++. Seine Effective C ++ und effektiver C ++ sind hoch Bücher empfohlen.

Ja, wenn Sie in die interne Dokumentation. Oder vielleicht ein libary Schreiben, die andere verwenden, damit sie sagen können, was geschieht, ohne dass die Dokumentation zu konsultieren. Werfen oder nicht werfen kann, einen Teil der API in Betracht gezogen wird fast wie der Rückgabewert.

Ich bin damit einverstanden, sie sind nicht wirklich nützlich Korrektheit Java-Stil in den Compiler für die Durchsetzung, aber es ist besser als nichts oder planlos Kommentare.

Sie können für Unit-Tests nützlich sein, so dass, wenn das Schreiben von Tests Sie wissen, was die Funktion zu erwarten zu werfen, wenn es fehlschlägt, aber es gibt keine Durchsetzung sie im Compiler umgibt. Ich denke, dass sie zusätzliche Code sind, die nicht notwendig ist in C ++. , Die Sie jemals alle wählen, die Sie sollten sicher sein, dass Sie den gleichen Codierungsstandard über das Projekt und die Teammitgliedern, so dass Ihr Code lesbar bleibt.

folgen

Aus dem Artikel:

http://www.boost.org/community/exception_safety.html

  

„Es ist allgemein bekannt zu sein, unmöglich   eine Ausnahme sichere generic schreiben   Dieser Anspruch Behälter.“Oft zu hören   unter Bezugnahme auf einen Artikel von Tom   Cargill [4], in dem er untersucht die   Problem der Ausnahme-Sicherheit für ein   generic-Stack-Vorlage. In seinem   Artikel wirft Cargill viele nützliche   Fragen, aber leider nicht zu   präsentiert eine Lösung für seine problem.1 Ihn   kommt zu dem Schluss, dass durch eine darauf hindeutet,   Lösung kann nicht möglich sein.   Leider wurde sein Artikel gelesen von   viele als „Beweis“ diese Spekulation.   Da es dort veröffentlicht haben   viele Beispiele für ausnahmefest   generischen Komponenten, darunter die C ++   Standardbibliothek Container.

Und in der Tat kann ich von Möglichkeiten denken Template-Klassen Ausnahme sicher zu machen. Es sei denn, Sie haben keine Kontrolle über alle Unterklassen dann können Sie ein Problem haben sowieso. Um dies zu tun könnte man typedefs in Ihren Klassen erstellen, die die Ausnahmen definieren, indem verschiedene Template-Klassen geworfen. Diese denken wird das Problem als Anheften es immer darauf an, im Gegensatz sie in von Anfang an zu entwerfen, und ich denke, es ist das Overhead, der die wirkliche Hürde ist.

Ausnahme Spezifikationen = Müll, fragen Sie einen Java-Entwickler im Alter von 30

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