2010-03-17 17 views
2

我想要派生一個字符串流,以便我可以使用運算符< <構造一條消息,然後將拋出該消息。該API將如下所示:派生streambuf或basic_ostringstream?

error("some text") << " more text " << 42 << std::endl; 

這應該做一個

throw "some text more text 42" 

因此,我所做的是使一個errorbuf(從流緩衝繼承)的重載「溢出」的方法,然後創建一個ostream( & errorbuf)。我不知道如果我不應該,而不是從basic_ostringstream什麼繼承...

回答

2

我會在這裏再次快步走了出去。我最喜歡的宏:

#define ATHROW(msg)            \ 
{                 \ 
    std::ostringstream os;           \ 
    os << msg;              \ 
    throw ALib::Exception(os.str(), __LINE__, __FILE__);   \ 
}                 \ 

在使用中:

ATHROW("Invalid value: " << x << " should be " << 42); 

異常類型是從我自己的圖書館,但我認爲你的想法。這比推導自己的流類要簡單得多,並且避免了很多令人討厭的併發症,如op < <()。

+0

有時,宏是最好的解決方案。 – 2010-03-23 13:55:26

3

你也許可以更容易做一樣的東西:

class error_builder 
{ 
public: 
    error_builder(const std::string& pMsg = "") 
    { 
     mMsg << pMsg; 
    } 

    ~error_builder(void) 
    { 
     throw std::runtime_error(mMsg.str()); 
    } 

    template <typename T> 
    error_builder& operator<<(const T& pX) 
    { 
     mMsg << pX; 

     return *this; 
    } 

private: 
    std::stringstream mMsg;  
}; 


error_builder("some text") << " more text " << 42 << std::endl; 

注意,像你這樣的,你不應該拋出字符串,因此我使用std::runtime_error。所有例外情況都應該來自std::exception,其中runtime_error的確如此,所有有意義的例外情況都可以通過使用const std::exception&來捕獲。

這是有效的,因爲臨時生命直到完整表達式結束。

+0

我不會真的扔爲const char * S 。這只是一個概念。 – 2010-03-17 07:51:46

+0

你不應該在析構函數中拋出異常(http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.3)。 – 2010-03-17 07:55:32

+0

@Helltone:這是一個例外。理解你不應該*的原因*(關鍵詞在這裏)拋出:在堆棧展開期間,如果兩個異常被激活,應用程序被終止。這顯然不是這種情況,因爲它打算立即拋出。 (公平地說,這個流*可能會失敗並拋出,但是meh。)編輯:好吧,無論如何修正它,所以你去了。 :) – GManNickG 2010-03-17 07:59:26

2

GMan的解決方案中缺少一些運營商。

class error { 
    public: 
    explicit error(const std::string& m = "") : 
      msg(m, std::ios_base::out | std::ios_base::ate) 
    {} 

    ~error() { 
     if(!std::uncaught_exception()) { 
     throw std::runtime_error(msg.str()); 
     } 
    } 

    template<typename T> 
    error& operator<<(const T& t) { 
     msg << t; 
     return *this; 
    } 

    error& operator<<(std::ostream& (*t)(std::ostream&)) { 
     msg << t; 
     return *this; 
    } 
    error& operator<<(std::ios& (*t)(std::ios&)) { 
     msg << t; 
     return *this; 
    } 
    error& operator<<(std::ios_base& (*t)(std::ios_base&)) { 
     msg << t; 
     return *this; 
    } 
    private: 
    std::ostringstream msg; 
}; 
0

我通常只是創建自己的異常類。你只需要重寫what(),並且可以提供儘可能多的構造函數。要構建錯誤消息,只需像上面那樣使用vasprintf(如果可用)或std :: ostringstream。

下面是一個例子:

class CustomException : public std::exception { 
private: 
    const std::string message; 
public: 
    CustomException(const std::string &format, ...) { 
     va_list args; 
     va_start(args, format); 
     char *formatted = 0; 
     int len = vasprintf(&formatted, format.c_str(), args); 
     if (len != -1) { 
      message = std::string(formatted); 
      free(formatted); 
     } else { 
      message = format; 
     } 
     va_end(args); 
    } 
    const char *what() const { 
     return message.c_str(); 
    } 
}; 

如果你沒有vasprintf,你也可以使用vsnprintf與堆棧的緩衝區...