C++基礎::自制異常定位器
我們經常會有這樣的需求,異常或錯誤(又或者記憶體洩露時)發生時,如何進行快速定位,定位到檔案一級、定位到函式一級、乃至定位到異常出現的行號一級。如此高大上的需求,只需要瞭解C++ preprocessor內建的一些巨集定義如__FILE__(檔名),__LINE__(行號),以及boost\current_function.hpp 中的BOOST_CURRENT_FUNCTION(函式名),將這些巨集定義以引數的形式傳遞給一個異常類,再施以一定的封裝,便可輕鬆實現對異常出現位置的捕捉。
#include <exception>
#include <boost\shared_ptr.hpp>
#include <sstream>
using namespace std;
class Error :public exception
{
public:
Error(const string& file, long line,
const string& func, const string& msg);
const char* what() const; // 重寫父類的what函式
private:
string format(const string& file, long line,
const string& func, const string& msg);
boost::shared_ptr<string> _msg;
// 操作_msg, 如同操作一個string*
};
Error::Error(const string& file, long line,
const string& func, const string& msg)
{
_msg = boost::shared_ptr<string>(new string(
format(file, line, func, msg)));
}
string format(const string& file, long line,
const string& func, const string& msg)
{
ostringstream oss; // #include <sstream>
oss << func << ":\n";
oss << file << "(" << line << ").\n" << msg;
return oss.str();
}
const char* Error::what() const
{
return _msg.c_str();
}
客戶端程式:
double divide(double x, double y)
{
if (y == 0.)
throw Error(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, "除數不能為0"); // #include <boost\current_function.hpp>
return x/y;
}
int main(int, char**)
{
try
{
divide(1., 0.);
}
catch(exception& e)
{
cout << e.what() << endl;
}
}
C++前處理器也提供瞭如下的巨集定義:
__DATE__
__TIME__
當然一種更常規的做法,利用巨集定義(也只能用巨集,而不可使用inline 行內函數取代,不由分說的原樣替換雖然臭名昭著,卻也有時非它不可)的原樣替換的特性,對此做進一步的封裝,避免顯式傳參的動作:
#define FAIL(msg)\
std::ostringstream oss; \
oss << msg; \
throw Error(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION,
oss.str());
#define ASSERT(predicate, msg)\
if (!(predicate)) \
{ \
FAIL(msg);\
}
這樣客戶端程式碼就可改寫為:
double divide(double x, double y)
{
if (y == 0.)
{
FAIL("除數不能為0");
// 這一點要尤其注意,一定要將FAIL放在if判斷的括號內部
// 如果不這樣做的話,if 預設後面的一條語句作為你if判斷成立時,要執行的動作
// 這樣FAIL巨集原樣替換的話,就無法識別oss << msg; 中的oss了
}
return x / y;
}
因為FAIL
巨集執行的動作是throw
拋異常,如果不對之進行捕獲的話,將由編譯器進行捕獲:
int main(int, char**)
{
double x = 1., y = 0.;
divide(x, y);
return 0;
}
編譯器將彈出如下視窗:
int main(int, char**)
{
try
{
double x = 1., y = 0.;
divide(x, y);
}
catch(exception& e)
{
cout << e.what() << endl;
}
return 0;
}
或者我們使用斷言的方式:
int main(int, char**)
{
try
{
double x = 1., y = 0.;
ASSERT(y != 0., "除數不能為0");
}
catch(exception& e)
{
cout << e.what() << endl;
}
return 0;
}
相關文章
- Java基礎-異常Java
- Java基礎 — 異常Java
- [Java基礎]異常Java
- Python基礎 -- 異常處理Python
- JavaSE基礎系列之異常Java
- Java基礎知識——異常Java
- Java基礎 ---Throwable異常類Java
- C++異常C++
- PHP基礎:異常處理ExceptionPHPException
- python 基礎之異常處理Python
- JAVA物件導向基礎--異常Java物件
- Java基礎異常整理(持續更新)Java
- 聊聊Java中的異常(基礎篇)Java
- Oracle開發基礎-異常處理Oracle
- PHP基礎之錯誤與異常PHP
- Java零基礎之異常(新手必看)Java
- C++ 異常機制(上)C++
- 【C++】 C++異常捕捉和處理C++
- Util應用框架基礎(五) - 異常處理框架
- Python基礎之錯誤和異常講解Python
- Java程式設計基礎20——異常&IO(File類)Java程式設計
- 錯誤和異常 (一):錯誤基礎知識
- C#基礎之前處理器,異常處理C#
- Python基礎之:Python中的異常和錯誤Python
- C++異常處理機制C++
- C++常見函式的基礎演算法C++函式演算法
- c++基礎C++
- 豬行天下之Python基礎——6.1 異常與斷言Python
- Python基礎入門知識點——Python中的異常Python
- Python基礎入門(7)- Python異常處理機制Python
- Java基礎之淺談異常與瞭解斷言Java
- C++錯誤和異常處理C++
- 在 C++ 中捕獲 Python 異常C++Python
- C++整理19_異常處理C++
- 傳智黑馬java基礎學習——day21(異常)Java
- 【躍遷之路】Java基礎練習(異常)(最後更新:2018.05.03)Java
- Linux基礎——BClinux8.2 排查vmcore異常當機問題Linux
- C++ 異常處理機制詳解:輕鬆掌握異常處理技巧C++
- C++ exception 異常類繼承關係C++Exception繼承