2010-06-07 79 views
3

我有某種意識形態的問題,所以:C++ - 在哪裏拋出異常?

假設我有一些模板函數

template <typename Stream> 
void Foo(Stream& stream, Object& object) { ... } 

這確實與此objectstream(例如東西,連載該對象流或類似的東西)。

比方說,我還添加一些簡單的封裝類,如(並假設這些包裝的數量等於2或3):

void FooToFile(const std::string& filename, Object& object) 
{ 
    std::ifstream stream(filename.c_str()); 
    Foo(stream, object); 
} 

所以,我的問題是:

在這種情況下(思想上),如果我的stream不好,我應該拋出異常嗎?我應該這樣做在每個包裝或只是動議通過檢查我的Foo,所以它的機身看起來像

if (!foo.good()) throw (something); 
// Perform ordinary actions 

我明白,這可能是沒有編碼的最重要組成部分,這些解決方案實際上是相等的,但我只是想知道「適當的」方式來實現這一點。

謝謝。

回答

5

在這種情況下,最好將它放在更低層的Foo函數中,這樣就不必在所有包裝中複製驗證和異常拋出代碼。一般情況下,正確使用異常可以通過刪除大量的數據驗證檢查來使代碼更加清晰,否則可能會在調用堆棧中的多個層次上進行冗餘。

+1

+1:避免剪切和粘貼是編程的最終目標:) – neuro 2010-06-07 15:47:33

1

越快抓住例外就越好。例外情況越具體 - 越好。除了聲明之外,不要害怕將大部分代碼包含在try catch塊中。

例如:

int count = 0; 
bool isTrue = false; 
MyCustomerObject someObject = null; 

try 
{ 
    // Initialise count, isTrue, someObject. Process. 
} 
catch(SpecificException e) 
{ 
// Handle and throw up the stack. You don't want to lose the exception. 
} 
1

我喜歡使用輔助功能此:

struct StreamException : std::runtime_error 
{ 
    StreamException(const std::string& s) : std::runtime_error(s) { } 
    virtual ~StreamException() throw() { } 
}; 

void EnsureStreamIsGood(const std::ios& s) 
{ 
    if (!s.good()) { throw StreamException(); } 
} 

void EnsureStreamNotFail(const std::ios& s) 
{ 
    if (s.fail()) { throw StreamException(); } 
} 

我之前和執行流操作,如果我不希望在發生故障後,立即對其進行測試。

1

傳統上在C++中,流操作不會拋出異常。這部分是由於歷史原因,部分原因是流式傳輸故障預計會出現錯誤。 C++標準流類處理這個問題的方式是在流上設置一個標誌,以表明發生了錯誤,哪些用戶代碼可以檢查。不使用異常使得恢復(流操作通常需要)比拋出異常更容易。

+0

儘管如此,如果在發生不好的事情時想要有異常,那麼總會有流對象的異常掩碼。在我看來,它應該設置爲* badbit *:正如你所說的那樣,除了eOF之外,還有提取失敗的情況,但是如果存在IO錯誤,那麼你可以做的事情不多,至少不是在你的「正常」文件讀/寫代碼。 – 2010-06-07 16:44:58

2

我不希望延遲通知錯誤。如果您在創建流之後知道它不好,爲什麼調用一個可用於它的方法?我知道,爲了減少代碼冗餘,您計劃進一步降低代碼冗餘。但這種方法的缺點是一個不太具體的錯誤信息。所以這在一定程度上取決於源代碼上下文。如果您可以在較低功能級別避免使用通用錯誤消息,則可以在其中添加代碼,這肯定會緩解代碼的維護,特別是在團隊中有新開發人員時。如果你需要一個特定的錯誤信息,那麼最好在失敗點處理它。

爲了避免代碼冗餘,請調用一個常見的函數,爲您創建此異常/錯誤。不要在每個包裝中複製/粘貼代碼。