西西軟件園多重安全檢測下載網(wǎng)站、值得信賴的軟件下載站!
軟件
軟件
文章
搜索

首頁編程開發(fā)VC|VC++ → 自己設(shè)計C++完善的異常處理類

自己設(shè)計C++完善的異常處理類

相關(guān)軟件相關(guān)文章發(fā)表評論 來源:本站整理時間:2010/10/31 9:24:39字體大。A-A+

作者:佚名點擊:390次評論:0次標簽: 異常處理

PeStudio編程輔助v8.42 綠色免費版
  • 類型:編程輔助大。699KB語言:英文 評分:5.0
  • 標簽:
立即下載
我們的異常處理類的features

如何寫一個異常處理類是一個不太容易的事情,最近剛好接觸了一些不錯的代碼,看到了一些技巧,這里和大家分享一下。

一個相對完善的異常處理類(以及附加的一些東西)應該能夠處理下面的一些功能:

1) 能夠方便的定義異常類的繼承樹

2) 能夠方便的throw、catch,也就是在代碼中捕獲、處理代碼的部分應該更短

3) 能夠獲取異常出現(xiàn)的源文件的名字、方法的名字、行號

4) 能夠獲取異常出現(xiàn)的調(diào)用棧并且打印出來

由于目前我用的平臺是linux,所以里面調(diào)用的一些函數(shù)也只是在linux下面有用。Windows也肯定是具有相應的函數(shù)的,具體可能需要去查查

首先科普一些內(nèi)容:

1) 對于沒有捕獲的異常(no handler),則會終止程序,調(diào)用terminate()

2) 在定義函數(shù)的時候,我們可以在定義的后面加上throw (exception1, exception2…):

    a) 如果沒有寫這一段、則可能拋出任意的異常

    b) 如果寫throw(),則表示函數(shù)不能拋出任意的異常

    c) 如果寫throw(A, B), 表示函數(shù)拋出A、B的異常

如果拋出的異常不在列表范圍內(nèi),則異常不能被catch,也就會調(diào)用terminate()

我們構(gòu)想一下我們定義、調(diào)用我們的異常類的時候是怎樣的一個情形:

1) 定義:

1:class DerivedException : public BaseException

2: {

3:public:

4: MY_DEFINE_EXCEPTION(DerivedException, BaseException);

5: };

2) 如何拋出異常

1: MY_THROW(DerivedException)

3) 如何catch異常

1:catch (DerivedException& e)

2: {

3: cout<< e.what() << endl;

4: }

這個輸出的內(nèi)容包括錯誤的行號、文件名、方法名、和調(diào)用棧的列表

給出我們異常類的頭文件:

1:#ifndef EXCEPTION_TEST

2:#define EXCEPTION_TEST

3: 

4:#include

5:#include

6: 

7:#define MY_THROW(ExClass, args...) \

8:do \

9: { \

10: ExClass e(args); \

11: e.Init(__FILE__, __PRETTY_FUNCTION__, __LINE__); \

12:throw e; \

13: } \

14:while (false)

15: 

16:#define MY_DEFINE_EXCEPTION(ExClass, Base) \

17: ExClass(const std::string& msg = "") throw() \

18: : Base(msg) \

19: {} \

20: \

21: ~ExClass() throw() {} \

22: \

23:/* override */ std::string GetClassName() const \

24: { \

25:return #ExClass; \

26: }

27: 

28:class ExceptionBase : public std::exception

29: {

30:public:

31: ExceptionBase(const std::string& msg = "") throw();

32: 

33:virtual ~ExceptionBase() throw();

34: 

35:void Init(constchar* file, constchar* func, int line);

36: 

37:virtual std::string GetClassName() const;

38: 

39:virtual std::string GetMessage() const;

40: 

41:constchar* what() constthrow();

42: 

43:const std::string& ToString() const;

44: 

45: std::string GetStackTrace() const;

46: 

47:protected:

48: std::string mMsg;

49:constchar* mFile;

50:constchar* mFunc;

51:int mLine;

52: 

53:private:

54:enum { MAX_STACK_TRACE_SIZE = 50 };

55:void* mStackTrace[MAX_STACK_TRACE_SIZE];

56: size_t mStackTraceSize;

57:mutable std::string mWhat;

58: };

59: 

60:class ExceptionDerived : public ExceptionBase

61: {

62:public:

63: MY_DEFINE_EXCEPTION(ExceptionDerived, ExceptionBase);

64: };

65: 

66:#endif

這個頭文件首先定義了兩個宏,這里先暫時不管他,我先來解釋一下ExceptionBase,它繼承自std::exception,std::exception里面其實已經(jīng)提供了一些功能了,但是比較弱,為了實現(xiàn)我們上文提到的功能,這里只是繼承了std:exception的借口,也就是what()函數(shù)。

上面的接口應該比較好理解,45行的GetStackTrace是打印當前的調(diào)用棧,49-51行分別存儲了當前出現(xiàn)exception的源文件名,函數(shù)名,行號,54行定義了最大的調(diào)用棧顯示的深度,也就是顯示50行。

60行顯示了怎樣定義一個新的異常類,這個就很方便了,通過MY_DEFINE_EXCEPTION宏去定義了一個繼承類,詳情見16行,這里不再細說,我這里想說說7行的MY_THROW宏,使用了3個內(nèi)置的參數(shù),__FILE__, __LINE__, __PRETTY_FUNCTION__, 他們分別是當前的文件名,行號,和函數(shù)名,他們的使用方法是在哪兒出現(xiàn),其相應的值就是什么。

為什么這里要使用MY_THROW宏呢?其實是為了方便的把行號、文件名等加入進來,宏展開的時候是在一行上的,這樣也使得行號與出錯的行號保持一致,而且讓代碼更簡單。

給出異常類的.cpp文件:

1:#include <execinfo.h>

2:#include <stdlib.h>

3:#include <cxxabi.h>

4: 

5:#include

6:#include

7: 

8:#include"exception_test.h"

9: 

10:usingnamespace std;

11: 

12: ExceptionBase::ExceptionBase(const std::string& msg) throw()

13: : mMsg(msg),

14: mFile(""),

15: mFunc(""),

16: mLine(-1),

17: mStackTraceSize(0)

18: {}

19: 

20: ExceptionBase::~ExceptionBase() throw()

21: {}

22: 

23:void ExceptionBase::Init(constchar* file, constchar* func, int line)

24: {

25: mFile = file;

26: mFunc = func;

27: mLine = line;

28: mStackTraceSize = backtrace(mStackTrace, MAX_STACK_TRACE_SIZE);

29: }

30: 

31: std::string ExceptionBase::GetClassName() const

32: {

33:return"ExceptionBase";

34: }

35: 

36:constchar* ExceptionBase::what() constthrow()

37: {

38:return ToString().c_str();

39: }

40: 

41:const std::string& ExceptionBase::ToString() const

42: {

43:if (mWhat.empty())

44: {

45: stringstream sstr("");

46:if (mLine > 0)

47: {

48: sstr << mFile << "(" << mLine << ")";

49: }

50: sstr << ": " << GetClassName();

51:if (!GetMessage().empty())

52: {

53: sstr << ": " << GetMessage();

54: }

55: sstr << "\nStack Trace:\n";

56: sstr << GetStackTrace();

57: mWhat = sstr.str();

58: }

59:return mWhat;

60: }

61: 

62: std::string ExceptionBase::GetMessage() const

63: {

64:return mMsg;

65: }

66: 

67: std::string ExceptionBase::GetStackTrace() const

68: {

69:if (mStackTraceSize == 0)

70:return"\n";

71:char** strings = backtrace_symbols(mStackTrace, 10);

72:if (strings == NULL) // Since this is for debug only thus

73:// non-critical, don't throw an exception.

74:return"\n";

75: 

76: std::string result;

77:for (size_t i = 0; i < mStackTraceSize; ++i)

78: {

79: std::string mangledName = strings[i];

80: std::string::size_type begin = mangledName.find('(');

81: std::string::size_type end = mangledName.find('+', begin);

82:if (begin == std::string::npos || end == std::string::npos)

83: {

84: result += mangledName;

85: result += '\n';

86:continue;

87: }

88: ++begin;

89:int status;

90:char* s = abi::__cxa_demangle(mangledName.substr(begin, end-begin).c_str(),

91: NULL, 0, &status);

92:if (status != 0)

93: {

94: result += mangledName;

95: result += '\n';

96:continue;

97: }

98: std::string demangledName(s);

99: free(s);

100:// Ignore ExceptionBase::Init so the top frame is the

101:// user's frame where this exception is thrown.

102://

103:// Can't just ignore frame#0 because the compiler might

104:// inline ExceptionBase::Init.

105: result += mangledName.substr(0, begin);

106: result += demangledName;

107: result += mangledName.substr(end);

108: result += '\n';

109: }

110: free(strings);

111:return result;

112: }

113: 

114:/*

115: * test-main

116: */

117:int f2()

118: {

119: MY_THROW(ExceptionDerived, "f2 throw");

120: }

121:void f1()

122: {

123:try

124: {

125: f2();

126: }

127:catch (ExceptionDerived& e)

128: {

129: cout << e.what() << endl;

130: }

131: }

132:int main()

133: {

134: f1();

135: }

這是函數(shù)的實現(xiàn)代碼,其他的都比較好理解,67行的GetStackTrace是相對復雜一點的,里面用backtrace函數(shù)去獲取了當前調(diào)用棧的層數(shù),用backtrace_symbols去獲取當前調(diào)用棧的符號,而且__cxa_demangle函數(shù)的使用也值得去看看,這里不再細說了。

117行后展示了一個測試代碼,代碼雖然定義比較麻煩,不過使用還是很方便的:)。

    相關(guān)評論

    閱讀本文后您有什么感想? 已有人給出評價!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過難過
    • 5 囧
    • 3 圍觀圍觀
    • 2 無聊無聊

    熱門評論

    最新評論

    發(fā)表評論 查看所有評論(0)

    昵稱:
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字數(shù): 0/500 (您的評論需要經(jīng)過審核才能顯示)