2013-03-05 85 views
5

我有一個簡短的問題。給定一個返回類的對象作爲結果的函數,如果沒有結果(說因爲索引超出範圍)應該返回什麼?我可以返回一個新的「空」對象,但我怎麼能指出沒有成功的計算?如何判斷沒有返回值的函數的結果?

我想有一個共同的方法。

+3

拋出異常http://www.cplusplus.com/doc/tutorial/exceptions/ – Tschallacka 2013-03-05 10:37:32

+3

拋出異常? – PlasmaHH 2013-03-05 10:37:40

+0

@MichaelDibbets。謝謝,我以前沒有用過。如果您將其寫成簡短的答案,我會將其標記爲已接受。 – danijar 2013-03-05 10:40:03

回答

2

當值與預期結果不匹配時,可以引發異常。

一個教程可以在http://www.cplusplus.com/doc/tutorial/exceptions

異常可與try和catch原則被發現。

程序「試圖」執行代碼。 如果發生意外事件,執行的代碼會「拋出」一個對象,變量或任何東西,這將被捕獲。 在catch語句中,您可以放置​​代碼如果發生意外事件應該發生的情況。

只需按照教程。

+0

只需指出,通過僅引發std :: exception和子類,您可以爲自己和其他人節省很多痛苦,因爲它們提供了獲取含義完整錯誤字符串'what()'的單一方法。拋出純int類型的值必須是可以完成的最糟糕的事情。 – josefx 2013-03-05 18:39:59

+0

但是拋出0xDEAD或0xBABE很有趣@josefx – Tschallacka 2013-03-06 07:37:48

13

C++中的常見方法是引發異常或使用一些包裝,如boost::optional

如果出現某種錯誤,應拋出異常,如果函數的有效用例返回空結果,那麼boost::optional -approach更合適。想到的一個例子是SQL的NULL。在我們的代碼庫中,boost::optional非常方便。

+0

作爲一個方面說明,在一些或多或少的近期視頻中,我看到* Alexandrescu *提出了一個'Exceptional'類型(它是這種方式嗎?),最後是'boost :: optional',第二個選項不是它是一個空值,但是是一個例外,因此在概念上適用於錯誤情況(與普通的'boost :: optional'相反)。否則聲音推理+1。 – 2013-03-05 15:39:14

+0

是的,也看到了,它叫'預計'。我沒有提到它的原因是我仍然認爲它既是實驗性的也是高級的。但對於高級讀者來說這是一個很好的傳情,所以這裏有一個[鏈接](http://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-在-C)。 – 2013-03-05 15:43:56

3

按照vector::at方法的哲學,如果可能,拋出out_of_range異常。

3

這取決於操作的語義。

如果錯誤發生後,你一定要拋出一個異常

#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(); 
} 

如果返回不值不表示錯誤狀態,您可以使用Boost.Optional。另外,只要你能創建X類型的「空」的對象,你能想到回來一對,其第二件是bool標誌,告訴我們第一個成員是否是一個有效的對象與否,如下的:

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

... 

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

感謝您提到Boost.Optional。 – danijar 2013-03-05 10:43:15

+0

值得注意的是,如果您可以創建一個類型爲「X」的空值,'std :: pair'解決方案纔有意義。然後,有時可以使用返回值的空白而不是'bool'。 – rodrigo 2013-03-05 11:43:14

+0

@rodrigo:我同意第一句話(將編輯,謝謝),而我不想只返回一個空白對象*:通過查看函數的簽名,'pair '已經給我一個提示, X'可能是空的。但我想這是一個品味問題。 – 2013-03-05 11:46:14

3

如果我們談論的是錯誤的情況,拋出異常是合適的解決方案。

#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; 
    } 
} 

如果允許有空值,可以爲該類指定一個特定值,例如:

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

爲什麼不是['std :: out_of_range'](http://en.cppreference.com/w/cpp/error/out_of_range)異常? – BoBTFish 2013-03-05 10:44:13

+0

這裏比較好,我對STL的例外沒有廣泛的瞭解。我會糾正這一點。 – Spook 2013-03-05 10:44:42

+0

感謝您的示例代碼。 – danijar 2013-03-05 10:45:02

0

您可以將枚舉與返回的對象類型配對。如果返回的枚舉值是特定值,則該對象有效,否則該對象處於無效狀態。

// 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 
    } 
} 

我可能只是拋出異常,而不是。