簡體   English   中英

如何在C ++中正確實現我自己的異常處理程序

[英]How to correctly implement my own exception handler in C++

我從C#轉到C ++,請原諒我,如果問題是基本的或有一些誤解......

我想構建自己的異常,以便在我的try / catch塊上使用。 我需要報告自定義異常代碼,自定義異常消息和自定義異常源 - 我可能擁有所有或部分參數。

所以我建了那個班:

CommonException.hpp

namespace exceptionhelper
{

    class CommonException : public std::exception {

    public:
        CommonException();
        CommonException(std::string message);
        CommonException(std::string source, std::string message);
        CommonException(int code, std::string source, std::string message);
        virtual ~CommonException();
        const char *what() const throw();


    private:
        int exceptionCode;
        std::string exceptionSource;
        std::string exceptionMessage;
    };

}

並實施:

CommonException.cpp

namespace exceptionhelper {
        CommonException::CommonException() {
            exceptionCode = 0;
            exceptionMessage = "No message.";
            exceptionSource = "No source.";
        }
        CommonException::CommonException(std::string message) {
            exceptionCode = 0;
            exceptionMessage = message;
            exceptionSource = "No source.";
        }
        CommonException::CommonException(std::string source, std::string message) {
            exceptionCode = 0;
            exceptionMessage = message;
            exceptionSource = source;
        }
        CommonException::CommonException(int code, std::string source, std::string message) {
            exceptionCode = code;
            exceptionMessage = message;
            exceptionSource = source;
        }
        CommonException::~CommonException() {
        }
        const char *CommonException::what() const throw()
        {
            std::stringstream s;
            s << "Code    : " << exceptionCode << std::endl;
            s << "Source  : " << exceptionSource << std::endl;
            s << "Message : " << exceptionMessage << std::endl;
            return s.str().c_str();
        }
    }

最后我的實施:

main ()
{
   try {
        ... code ...

        throw new CommonException(10, "here", "test exception");

   }
   catch (const std::exception &exc)
   {
            std::cerr << "Exception detected:" << std::endl;
            std::cerr << exc.what();
        }
        catch (...)
        {
            std::cerr << "Unknown exception called." << std::endl;
            throw;
        }
}

出於某種原因,我得到了這個結果:

Unknown exception called.
terminate called after throwing an instance of 'linuxcommon::exceptionhelper::CommonException*'
Aborted (core dumped)

問題:

a)為什么我沒有捕獲自定義異常? b)我非常確定有更好的方法來進行這種異常處理,但我還是無法解決這個問題......

謝謝你的幫助......

您的代碼的一些注釋。

  1. 您可能希望從std::runtime_error (而不是std::exception )派生異常類,因為std::runtime_error已經為構造函數提供了錯誤消息字符串。 當然,您可以將自己的異常數據成員添加到派生類中。

  2. 您不需要為異常類定義具有空主體的虛擬析構函數,因為您沒有要執行的顯式清理代碼。 std::exception有一個虛析構函數,對你的派生異常類來說效果很好。

  3. 您可以使用更慣用的C ++語法在構造函數中初始化異常數據成員,例如,而不是:

 CommonException::CommonException() { exceptionCode = 0; exceptionMessage = "No message."; exceptionSource = "No source."; } 

您可以使用:

CommonException::CommonException()
  : exceptionCode(0), 
    exceptionMessage("No message."), 
    exceptionSource("No source.")
{ }
  1. 如果傳遞字符串參數,您仍然可以按值傳遞,但您可能希望從值中使用std::move()來初始化數據成員,例如,而不是:
 CommonException::CommonException(std::string source, std::string message) { exceptionCode = 0; exceptionMessage = message; exceptionSource = source; } 

你可以做:

CommonException::CommonException(std::string source, std::string message) 
    : exceptionCode(0),
      exceptionMessage(std::move(message)),
      exceptionSource(std::move(source))
{
}
  1. 考慮使單字符串參數構造函數explicit ,以防止從字符串到異常的偽隱式轉換:

     explicit CommonException(std::string message); 
  2. 在當前形式中,你的what()方法實現可以拋出,因為在std::stringstream上插入操作( << )可以拋出:

 const char *CommonException::what() const throw() { std::stringstream s; s << "Code : " + exceptionCode << std::endl; s << "Source : " + exceptionSource << std::endl; s << "Message : " + exceptionMessage << std::endl; return s.str().c_str(); } 

因此,刪除throw()規范,簡單地說:

const char* CommonException::what() const

(作為旁注,現代C ++ 11將方法標記為非拋出的方法是使用noexcept )。

您可能還想簡單地使用'\\n'而不是std::endl來避免過早的悲觀化。

此外,您在此行返回一個臨時字符串:

  return s.str().c_str(); 

返回給調用者的const char*指針只會指向調用站點上的一些垃圾:這會引入一個錯誤。

要解決這個問題,您可能需要考慮添加一個std::string數據成員,在異常對象構造期間格式化該數據成員內的整個錯誤消息字符串(即在構造函數中 - 您也可以構建一個私有幫助器方法來執行此操作,避免在每個構造函數中重復代碼),並從what()方法返回m_str.c_str()

如果從std::runtime_error派生異常類,則可以在構造時構建整個錯誤消息字符串,並將其傳遞給std::runtime_error的構造函數。 在這種情況下, std::runtime_error::what()將執行正確的操作,並且您不需要覆蓋異常類中的what()

例如

// Derive from std::runtime_error instead of std::exception
class CommonException : public std::runtime_error

...

CommonException::CommonException( /* your exception data */ )
    : std::runtime_error(BuildErrorMessage( /* your exception data */ )
{ }

// Private helper method
std::string CommonException::BuildErrorMessage( /* your exception data */ )
{
    // Build your exception message string here,
    // e.g. you can use std::ostringstream here,
    // and just call its str() method
    // to return the whole error message string.
    ...
}

在例外的“客戶”方面,您有:

  ... code ... throw new CommonException(10, "here", "test exception"); } catch (const std::exception &exc) 

相反,考慮按值拋出,而不是在堆上動態分配異常對象,例如,只需:

throw CommonException( /* your exception data*/ );

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM