2017-09-26 81 views
0

我寫一個C風格的功能:如何在C++中設計錯誤代碼?

enum { 
    EFUNC1, 
    EFUNC2, 
} 

int func0() { 
    int err = 0; 
    if((err=func1())!=0) { 
     // return err or return EFUNC1 
    } 

    if((err=func2())!=0) { 
     // return err or return EFUNC2 
    } 
    return 0; 
} 

FUNC1和FUNC2是C函數和他們有自己的錯誤代碼。當func1或func2返回錯誤時我該怎麼辦?我想辦法:

  1. 設計我的錯誤代碼。錯誤代碼的數量是func1和func2的總和。當調用堆棧較深時,錯誤代碼的數量變大。

  2. 只需返回func1或func2的結果。由於錯誤代碼可能重疊,因此無法知道哪個功能失敗。

  3. 設計我的錯誤代碼和代碼的數量等於函數的數量。調用者只知道哪個函數返回錯誤,但他不知道進一步的原因。

  4. 拋出包含失敗函數名稱及其錯誤代碼的異常。

最佳做法是什麼?


上面的代碼示例不明確。我修改了它。

+9

你的想法是有點瑕疵。調用'func1'和'func2'是'func0'的一個實現細節。您不應該報告哪個功能失敗,而是**爲什麼發生故障**。這是強大的,更好的做法。這樣,沒有人需要深入調用圖表來了解錯誤。 – StoryTeller

+2

如果'func1()'失敗並且需要向調用者報告錯誤,那麼爲什麼你甚至試圖調用'func2'? – user463035818

+0

@ tobi303示例不完整。我只是表明func0會調用func1和func2。我沒有添加任何錯誤處理代碼。 – CppLucifer

回答

2

爲什麼將func0()的複雜性暴露給調用者?通常調用者對函數體內發生的事情不感興趣,他只是想完成這項工作。

func0()應該通知用戶它爲什麼沒有完成它的目標(終止沒有錯誤)。他們有很多方法可以做到這一點。一個例子可能是這樣的:

// On success: Return 0 
// On error: Return -1 
int func0() { 
    if(func1() == -1) { 
     printf("Error in func0: func1 returned error code -1"); 
     return -1; 
    } 
    if(func2() == -2) { 
     printf("Error in func0: func1 returned error code -2"); 
     return -1; 
    } 
    return 0; 
} 

注意,這裏我們不允許func2()如果func1()不能被執行,因爲這可能是危險的。

例如,如果func1()是假設一個數組func2()將使用分配空間,然後讓我們說,func1()失敗(因爲malloc()失敗)。 func2()應該調用而不是,因爲func1()在這種情況下失敗,因爲func2()預期可以使用的數組在運行時不可用。

+0

我修改了代碼。現在更清楚了,謝謝。簡單地返回true或false很容易,但它隱藏了細節。調用者對func0調用的函數不感興趣,但他可能對func0失敗時的原因感興趣。真假是不夠的。 – CppLucifer

0

呼應tobi303's comment,後面的錯誤代碼的邏輯如下:

  1. 如果當在某個子程序(func1)發生錯誤的例程(func0)將失敗,則例程應立即停止對錯誤並向調用者報告。

    否則就沒有意義了。例如,如果func0是用來製作咖啡的,func1是用來製作咖啡豆的,而func2是用來製作咖啡的,那麼如果沒有咖啡豆,那麼你只是在醞釀空氣。告訴別人不能釀造空氣不是非常有幫助的。

  2. 如果一個例程可以優雅地處理其子例程中的錯誤,那麼它對於例程的調用者來說並不是一個錯誤。在這種情況下,不應該返回錯誤。

所以你的程序的第一個情況下,結構應簡單地

int func0() 
{ 
    if(int err = func1()) 
     return err; 
    if(int err = func2()) 
     return err; 
    return 0; 
} 

和第二筐

int func0() 
{ 
    if(int err = func1()) 
     handle(err); 
    if(int err = func2()) 
     return err; 
    return 0; 
}