2013-03-05 4 views
5

Ich habe eine kurze Frage. Bei einer Funktion, die ein Objekt einer Klasse als Ergebnis zurückgibt, was soll ich zurückgeben, wenn es kein Ergebnis gibt (sagen wir, weil ein Index außerhalb des Bereichs liegt)? Ich könnte ein neues "leeres" Objekt zurückgeben, aber wie kann ich darauf hinweisen, dass es keine erfolgreiche Berechnung gab?Wie kann man sagen, dass es kein Ergebnis einer Funktion mit Rückgabewert gibt?

Ich vermute, es gibt einen gemeinsamen Ansatz.

+3

eine Ausnahme werfen http://www.cplusplus.com/doc/tutorial/exceptions/ – Tschallacka

+3

eine Ausnahme auslösen? – PlasmaHH

+0

@MichaelDibbets. Danke, ich hatte das vorher nicht benutzt. Wenn du das als kurze Antwort schreibst, werde ich es als akzeptiert markieren. – danijar

Antwort

2

Sie können eine Ausnahme auslösen, wenn die Werte nicht den erwarteten Ergebnissen entsprechen.

Ein Tutorial kann mit einem try und catch Prinzip Eine Ausnahme arbeitet bei http://www.cplusplus.com/doc/tutorial/exceptions

finden.

Ein Programm "versucht" Code auszuführen. Wenn etwas Unerwartetes passiert, "wirft" der ausgeführte Code ein Objekt, eine Variable oder was auch immer, und dies wird abgefangen. In der catch-Anweisung können Sie Code eingeben, was passieren soll, wenn das Unerwartete passiert ist.

Folgen Sie einfach dem Tutorial.

+0

Nur um darauf hinzuweisen, können Sie sich selbst und allen anderen eine Menge Schmerz ersparen, indem Sie nur std :: exception und subclasses werfen, da sie einen einzigen Weg bieten, um eine Bedeutung voller Fehlerzeichen 'what()' zu bekommen. Das Werfen von einfachen int char-Werten muss das Schlimmste sein, was man machen kann. – josefx

+0

Aber werfen 0xDEAD oder 0xBABE macht Spaß @josefx – Tschallacka

13

Der übliche Ansatz in C++ ist entweder eine Ausnahme zu werfen oder einen Wrapper wie boost::optional zu verwenden.

Eine Ausnahme sollte ausgelöst werden, wenn es sich um eine Art von Fehler handelt, der boost::optional -Verbund ist geeigneter, wenn es ein gültiger Anwendungsfall Ihrer Funktion ist, ein leeres Ergebnis zurückzugeben. Ein Beispiel, das mir in den Sinn kommt, ist SQL's NULL. boost::optional erwies sich als ziemlich praktisch in unserer Codebasis.

+0

Als Randnotiz sah ich in einem mehr oder weniger aktuellen Video * Alexandrescu * einen 'Exceptional'-Typ vorschlagen (hieß es so?), Der am Ende ein' boost :: optional' ist, mit der zweiten Option nicht ist ein leerer Wert, aber eine Ausnahme, und wäre daher konzeptionell geeignet, um für Fehlerfälle verwendet zu werden (im Gegensatz zu einem einfachen "boost :: optional"). Sonst vernünftiges Denken +1. –

+0

Ja, habe das auch gesehen und es heißt 'Erwartet '. Der Grund, warum ich es nicht erwähnt habe, ist, dass ich es immer noch als * experimentell und fortgeschritten * betrachte. Aber es ist ein guter Teaser für fortgeschrittene Leser, also hier ist ein [Link] (http://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling- in-C). –

3

Nach der Philosophie der vector::at Methode gehen out_of_range Ausnahme wenn möglich.

3

Es hängt davon ab, was die Semantik der Operation ist.

Wenn ein Fehler aufgetreten ist, sollten Sie auf jeden Fall eine Ausnahme werfen:

#include <stdexcept> // Necessary for standard exceptions 

X foo() 
{ 
    ... 
    if (/* something goes wrong... */) 
    { 
     // There may be a more appropriate exception class. You could 
     // also derive your own exception class from std::exception... 
     throw std::logic_error("Whatever!"); 
    } 

    ... 
} 

... 

try 
{ 
    X x = foo(); 
    // Work with x... 
} 
catch (std::logic_error const& e) // Catch what is appropriate... 
{ 
    std::cout << e.what(); 
} 

Wenn ein nicht-Wert zurückgegeben wird keine Fehlerbedingung nicht bezeichnen, könnten Sie Boost.Optional verwenden. Alternativ, vorausgesetzt, Sie können ein „leeres“ Objekt des Typs erstellen X, Sie ein Paar Rückkehr dessen zweites Element denken könnte, ist ein bool Flag, das das erste Element gibt an, ob ein gültiges Objekt ist oder nicht, wie unten:

std::pair<X, bool> foo(); 

... 

bool valid; 
X x; 
std::tie(x, valid) = foo(); 
if (valid) 
{ 
    // Use x... 
} 
+0

Danke für die Erwähnung von Boost.Optional. – danijar

+0

Es ist erwähnenswert, dass die 'std :: pair' Lösung nur sinnvoll ist, wenn Sie einen leeren Wert vom Typ' X' erstellen können. Und dann kann manchmal die Leere des Rückgabewertes anstelle des 'bool' verwendet werden. – rodrigo

+0

@rodrigo: Ich stimme dem ersten Satz zu (werde editieren, danke), während ich kein leeres Objekt zurückgeben möchte * nur *: Das Paar gibt mir durch einen Blick auf die Signatur der Funktion schon einen Hinweis darauf X' könnte leer sein. Aber ich denke, es ist Geschmackssache. –

3

Wenn wir über eine fehlerhafte Situation sprechen, ist das Auslösen einer Ausnahme die richtige Lösung.

#include<exception> 

Object * GenerateObject(int i) 
{ 
    if (i < 0) 
     throw std::out_of_range("i"); 

    return new Object(i); 
} 

int main(int argc, char * argv[]) 
{ 
    try 
    { 
     Object * obj = GenerateObject(-1); 

     // Succeeded 
     return 0; 
    } 
    catch (std::exception & e) 
    { 
     // Failed, exiting with error value 
     return 1; 
    } 
} 

Wenn ein leerer Wert zulässig ist, können Sie einen bestimmten Wert für diese Klasse angeben, z.

class Rectangle 
{ 
private: 
    int left, top, width, height; 

public: 
    Rectangle(l, t, w, h) 
    { 
     left = l; 
     top = t; 
     width = w; 
     height = h; 
    } 

    public static Rectangle empty; 
} 

Rectangle Rectangle::empty = Rectangle(0, 0, -1, -1); 

// ... 

Rectangle DoSth(int i) 
{ 
    // i < 0 is NOT considered an error here 
    if (i < 0) 
      return Rectangle::empty; 

    // Further processing 
} 
+1

Warum nicht eine ['std :: out_of_range'] (http://en.cppreference.com/w/cpp/error/out_of_range) Ausnahme? – BoBTFish

+0

Es ist besser hier, ich habe keine umfassenden Kenntnisse der Ausnahmen von STL. Ich werde das korrigieren. – Spook

+0

Danke für den Beispielcode. – danijar

0

Sie können eine Enumeration mit dem zurückgegebenen Objekttyp paaren. Wenn die zurückgegebene Enumeration ein bestimmter Wert ist, ist das Objekt gültig, andernfalls befindet sich das Objekt in einem ungültigen Zustand.

// This is a working C++11 example. 
#include <utility> 
#include <memory> 

enum result 
{ 
    ok, 
    out_of_range, 
    some_other_error 
}; 

class object 
{ 
    public: 
     object() {} 
}; 

typedef std::shared_ptr<object> object_ptr; 

typedef std::pair< result, object_ptr > return_type; 

return_type some_function(int index) 
{ 
    if (index > 5) 
    { 
     return return_type{ result::out_of_range, nullptr }; 
    } 

    return return_type{ result::ok, object_ptr{ new object() } }; 
} 

int main() 
{ 
    return_type res = some_function(10); 
    if (res.first == result::ok) 
    { 
     // Do something with res.second 
    } 
    else 
    { 
     // Handle the error 
    } 
} 

Ich würde wahrscheinlich nur eine Ausnahme stattdessen werfen.