2013-12-11 55 views
2

我想寫一個類來處理異常。我認爲增加一個<運營商給我一個簡單的方法來拋出錯誤信息會很有用。貝婁是我迄今爲止解決這個問題的方法。有一件事情是讓我煩惱的是,如果我在析構函數中刪除流(如我的代碼所示),我會得到一個段錯誤。 Bellow是我的異常處理類的完整代碼。我不知道在析構函數達到它之前可能會刪除流。段錯誤刪除類成員指針流

class prc_exception : public std::exception { 
    private: 
    int line_num; 
    std::ostringstream* msg; 

    public: 
    prc_exception(const char* part, const int line) throw() 
    : exception() { 
     msg = new std::ostringstream(); 
     *msg << "<parcer:" << part << ":" << line << ">: "; 
    } 
    ~prc_exception() throw() { delete msg; } 
    virtual const char* what() const throw() { return msg->str().c_str(); } 
    virtual const int line() const throw() { return line_num; } 
    template <class T> prc_exception& operator<<(const T& rhs) 
    { *msg << rhs; return (*this); } 
}; 

此外,如果有人可以建議一個更好的方式來處理我想要做的事情,請給我一個建議。 我想有可用這樣一個東西:

throw prc_exception("code_part",__LINE__) << "More info"; 

,當抓到會有它就是()函數返回一個字符串,如:

<parcer:code_part:36>: More info 

非常感謝。

已解決: 正如@polkadotcadaver建議的那樣,添加一個Copy構造函數和一個複製賦值操作符修復了這個問題。固定代碼發揮預期的作用: 的#include 的#include

using namespace std; 

class prc_exception : public std::exception { 
    private: 
    int line_num; 
    std::ostringstream msg; 

    public: 
    prc_exception(const char* part, const int line) throw() 
    : exception() { 
     msg << "<parcer:" << part << ":" << line << ">: "; 
    } 
    /** Copy Constructor */ 
    prc_exception (const prc_exception& other) 
    { 
     line_num = other.line(); 
     msg << other.what(); 
    } 
    /** Copy Assignment Operator */ 
    prc_exception& operator= (const prc_exception& other) 
    { 
     line_num = other.line(); 
     msg << other.what(); 
     return *this; 
    } 
    ~prc_exception() throw() { } 

    virtual const char* what() const throw() { return msg.str().c_str(); } 
    virtual const int line() const throw() { return line_num; } 
    template <class T> prc_exception& operator<<(const T& rhs) 
    { msg << rhs; return (*this); } 
}; 

int main() 
{ 
    try 
    { 
    throw prc_exception("hello", 5) << "text." << " more text."; 
    } catch (exception& e) { 
    cout << e.what() << endl; 
    } 

    return 0; 
} 
+0

查一查怎麼寫拷貝賦值運算符在這樣的情況下,複製和交換成語(請注意,我還沒有嘗試過!) – polkadotcadaver

回答

2

以下的答案必須是一個假設的東西,因爲我沒有,你使用類是的代碼。如果我吠叫錯了樹,請說!

好的,這是一個可編譯的,可運行的測試程序,完成後沒有任何問題。

#include <iostream> 
#include <sstream> 

using namespace std; 

class prc_exception : public std::exception { 
    private: 
    int line_num; 
    std::ostringstream* msg; 

    public: 
    prc_exception(const char* part, const int line) throw() 
    : exception() { 
     msg = new std::ostringstream(); 
     *msg << "<parcer:" << part << ":" << line << ">: "; 
    } 
    ~prc_exception() throw() { delete msg; } 
    virtual const char* what() const throw() { return msg->str().c_str(); } 
    virtual const int line() const throw() { return line_num; } 
    template <class T> 
    prc_exception& operator<<(const T& rhs) 
    { *msg << rhs; return (*this); } 
}; 

int main() 
{ 
    try 
    { 
     throw prc_exception("hello", 5); 
    } 
    catch (prc_exception& e) 
    { 
     e << "Oh dear"; 

     cout << e.what() << endl; 
    } 

    return 0; 
} 

我覺得你可以做的是通過捕獲異常如參考反對:

try 
    { 
     throw prc_exception("hello", 5); 
    } 
    catch (prc_exception& e) 
    { 
     e << "Oh dear"; 

     cout << e.what() << endl; 
    } 

...現在它出現segfaults,它打印輸出後的預期。原因是兩件事的結合。

首先,你有一個錯誤的複製構造函數。由於您自己沒有定義複製構造函數,因此編譯器爲您生成了一個。它的默認行爲是複製你的類的每個成員 - 當你有像你的ostringstream這樣的堆分配成員時,這是不好的。

認爲它是這樣的(不要認爲這意味着異常應該new'd,他們不應該!):當你通過值捕獲異常

// This creates an ostringstream, let's call it Bob 
prc_exception* an_exception = new prc_exception{"hello", 5}; 

// This SHARES the first ostringstream, Bob, as it just copied the pointer, 
// NOT what it was pointing to. 
prc_exception* a_second_exception = new prc_exception{an_exception}; 

// Delete the original exception. This calls ~prc_exception and deletes Bob 
delete an_exception; 

// WHOOPS we just deleted Bob again, because we were pointing to it. 
// This causes the crash. 
delete a_second_exception 

,因爲我懷疑你是,這會複製異常。最佳做法是始終通過參考來捕捉異常。

但是很關鍵的是,如果您創建了一個具有一個或多個堆分配成員的類,那麼您也可以編寫自己的拷貝構造函數,複製賦值運算符和析構函數。谷歌爲三規則(請參閱下面的參考,其他微妙之處適用)。

我實際上沒有看到堆分配你的流的原因。只要有一個ostringstream作爲成員 - 我懷疑你最初做了這件事,但得到了一個編譯錯誤,你通過價值發現了異常。這是因爲ostringstream不可複製!

所以你的解決方法是明確的:

  • 充分利用ostringstream成員沒有新-ING它。廢棄析構函數。
  • 通過引用捕獲異常。

參考資料:

Problem with ostringstream and copy constructor

http://www.gotw.ca/gotw/069.htm

https://en.wikipedia.org/wiki/Rule_of_three_(C++_programming)

+1

非常感謝@polkadotcadaver。我學到了一些新東西。由於複製它的問題,我確實做了一個指向流成員的指針,這是你指出的。儘管如此,我仍然在引用。 – SU3