2015-11-02 27 views
1

我想拋出一個異常,提供有關哪些輸入/結果導致問題的更詳細的信息。然後,我可以將有用的錯誤消息記錄到日誌中,同時捕獲這些異常。我正在處理VS2012,它沒有實現參數包。所以目前我使用vsprintf將可變長度參數合併到字符串中。在異常構造函數中參數化錯誤消息是否是一種好的做法?

  1. 它是一個很好的做法,使用這種printf-like功能在錯誤處理階段?

  2. 或者它只是不需要在異常中攜帶這些細節信息?

異常

class VargException : std::exception 
{public: 
    VargException (const char* fmt, ...) 
    { 
     va_list vargs; 
     va_start(vargs, fmt); 
     char buf[260] = {}; 
     vsprintf_s(buf, fmt, args); 
     va_end(vargs); 
     msgBuilt_ = tryAssign(msg_, buf); 
    } 
    const char* what() const { 
     return msgBuilt_? msg_.c_str(): "Error message failed to build"; 
    } 
    std::string msg_; 
    bool msgBuilt_; 

    // Updated: Avoid dynamic std::string throw exception 
    bool tryAssign(std::string& msg, const char* buf) throw() 
    { 
     try{ msg = buf; return true;} 
     catch (...) { return false; } 
    } 
}; 

客戶端代碼

void func(int key, int len) { 
    try { 
     if(notExists(key)) { throw VargException("%d key does not exist", key); } 
     if(outOfRange(len)) { throw VargException("length %d is out of range.", len); } 
     HRESULT hr = processSomething(); 
     if(FAILED(hr)) { throw VargException("FAILED to processingSomething. hr: 0x%08X", hr); } 
    } catch (VargException& e) { 
     std::cerr << e.what() << "\n"; 
    } 
} 
+1

@BaummitAugen'std :: exception'實際上沒有。 'logic_error'和'runtime_error'。 –

+1

可以說'vsprintf'不是類型安全的。 – Jason

回答

2

在異常創建/處理代碼中,您應該對異常更偏執。

構建std::string可以throw.

我想補充一點偏執,否則接受設計。查找一些令牌以檢測2013模式併發出警告/棄用消息。

+0

是的,我從來沒有想過創建std :: string可能會失敗。這應該小心。但是,如果動態字符串有機會失敗,是否意味着通過合併變量參數來構建結果消息很困難,同時拋出異常? (不管vsprintf/std :: stringstream/string :: opeator +) –

+0

這是否意味着我們應該在錯誤處理階段保持任何操作的簡單。固定字符串文字看起來像最安全的選項。 –

+0

我編輯的帖子增加了一個tryAssign函數來處理std :: string賦值,以避免從std :: string引發的異常。這可能更安全。 –

1

這似乎是一個合理的方法(除非你錯過了一個參數vsprintf_s)。

只要確保使用可變參數模板和I/O流將其交換爲類型安全的解決方案。
當你可以。

1

我發現它更容易使用std :: ostringstream而不是格式化字符串。

例如:

class MessageBuilder 
{ 
public: 
    MessageBuilder() {}; 

    MessageBuilder(const char * context) 
    { 
     m_os << context << ": "; 
    } 

    // stream operator to build message 
    template <class T> 
    MessageBuilder & operator<<(const T & t) 
    { 
     m_os << t; 
     return *this; 
    } 

    operator std::string() const 
    { 
     return m_os.str(); 
    } 

private: 
    std::ostringstream m_os; 
}; 

哪個可以用於這樣建立的消息。

MessageBuilder() << "This is a message containing an int: " << 3; 
相關問題