17 Stimmen

Wie kann man dem Compiler signalisieren, dass eine Funktion immer einen Fehler verursacht?

Beim Aufruf von Funktionen, die immer aus einer Funktion werfen, die einen Wert zurückgibt, warnt der Compiler oft, dass nicht alle Kontrollpfade einen Wert zurückgeben. Das ist legitim.

void AlwaysThrows() { throw "something"; }

bool foo()
{
    if (cond)
        AlwaysThrows();
    else
        return true; // Warning C4715 here
}

Gibt es eine Möglichkeit, den Compiler zu sagen, dass AlwaysThrows tut, was es sagt?

Ich bin mir bewusst, dass ich eine weitere throw nach dem Funktionsaufruf:

{ AlwaysThrows(); throw "dummy"; }

Und ich weiß, dass ich die Warnung explizit deaktivieren kann. Aber ich habe mich gefragt, ob es eine elegantere Lösung gibt.

29voto

Andrew Tomazos Punkte 62162

Verwenden Sie die noreturn Attribut. Dies wird im Abschnitt "7.6.3 Attribut Noreturn [dcl.attr.noreturn]" der neuesten Version der C++-Norm, dritte Ausgabe ISO/IEC 14882:2011.

Beispiel aus der Norm:

[[ noreturn ]] void f()
{
    throw "error";
}

5voto

Jesse Hall Punkte 5855

Sie könnten eine Dummy-Rückgabeanweisung nach dem Aufruf von AlwaysThrows() einfügen, mit einem Kommentar, der erklärt, warum sie da ist. Dies ist auch nützlich, wenn die Funktion, die Sie aufrufen, immer exit()s oder abort()s.

4voto

Michael Punkte 52790

Mit Visual C++ können Sie __declspec(noreturn) .

3voto

Natürlich stellt sich die Frage, warum man einen solchen Code überhaupt schreiben sollte. Die offensichtliche Antwort darauf ist, dass AlwaysTrows() eigentlich eine Art Fehlerberichtsfunktion ist. In meinem eigenen Code verwende ich ein Makro für die Fehlerberichterstattung, weil ich damit die Formatierung von Zeichenketten durchführen und die Standardwerte abrufen kann. __LINE__ y __FILE__ Makros. Das Makro sieht ungefähr so aus:

#define ATHROW( msg )                                               \
{                                                                   \
    std::ostringstream os_;                                         \
    os_ << msg;                                                     \
    throw ALib::Exception( os_.str(), __LINE__, __FILE__ );         \
}

wobei der Ausnahmekonstruktor alle zusätzlichen Formatierungen, Protokollierungen usw. vornimmt. Ein Nebeneffekt davon ist natürlich, dassv der Compiler sehen kann, dass eine Ausnahme ausgelöst wird, so dass, wenn ich etwas wie sagen:

int f() int val ) {
   if ( val >= BADVALUE ) {
       ATHROW( "Invalid value " << val << " for val" );
   }
   else {
       return val / 3;
   }
}

dann erhalte ich keine Warnung, dass f() keinen Wert zurückgibt.

1voto

Ich habe auch dieses lästige kleine Problem. Normalerweise beinhaltet das Szenario:

  1. Es gibt ein paar gemeinsame Codezeilen in mehreren Catch-Blöcken, die ich gerne überarbeiten würde
  2. Alle vorgenannten Auffangblöcke werfen die Ausnahme letztendlich zurück.

Sie können zwar einen Dummy-Return nach der Always-Throwing-Methode einfügen, aber das wird wahrscheinlich die Zwangsstörung Ihres Programmierers verletzen.

Der Kompromiss, den ich verwende, besteht darin, dass die aufgerufene Methode die Ausnahme nicht auslöst, sondern sie zurückgibt. Dann, wenn Sie die Methode aufrufen, werfen Sie einfach den Rückgabewert:

Exception HandleException() 
{ 
    // Do stuff, like some logging maybe
    return SomeException("something"); 
}

bool foo()
{    
   if (cond)        
       throw HandleException();    
   else        
       return true; // no more warning
}

Auf diese Weise müssen Sie keine zusätzlichen Codezeilen hinzufügen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X