[英]Getting information about where c++ exceptions are thrown inside of catch block?
我有一個 C++ 應用程序,它在 try 塊中包裝了大部分代碼。 當我捕獲異常時,我可以將用戶返回到穩定狀態,這很好。 但我不再收到崩潰轉儲。 我真的很想弄清楚異常發生在代碼中的哪個位置,以便我可以記錄並修復它。
能夠在不停止應用程序的情況下進行轉儲是理想的,但我不確定這是否可能。
有什么方法可以找出從 catch 塊中拋出異常的位置嗎? 如果有用,我將在 windows xp 及更高版本上使用本機 msvc++。 我的計划是簡單地將崩潰記錄到不同用戶機器上的文件中,然后在崩潰日志達到一定大小后上傳。
這可以通過使用 SEH(結構化異常處理)來實現。 關鍵是 MSVC 通過 SEH 實現了 C++ 異常。 另一方面,純 SEH 更加強大和靈活。
這就是你應該做的。 而不是像這樣使用純 C++ try/catch 塊:
try
{
DoSomething();
} catch(MyExc& exc)
{
// process the exception
}
您應該使用 SEH 塊包裝內部代碼塊DoSomething
:
void DoSomething()
{
__try {
DoSomethingInner();
}
__except (DumpExc(GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH) {
// never get there
}
}
void DumpEx(EXCEPTION_POINTERS* pExc)
{
// Call MiniDumpWriteDump to produce the needed dump file
}
也就是說,在 C++ try/catch 塊中,我們放置了另一個原始 SEH 塊,它只轉儲所有異常而不捕獲它們。
有關使用 MiniDumpWriteDump 的示例,請參見此處。
可以將例外設計為包含源文件名和行號。 為此,您需要創建一個從std::exception
派生的類來包含信息。 在下面的示例中,我的應用程序有一個異常庫,包括my_exception
。 我還有一個traced_error
,它是從我的應用程序級異常派生的模板異常類。 traced_error
異常包含文件名和行號信息,並調用應用程序級異常類的what()
方法獲取詳細的錯誤信息。
#include <cstdlib>
#include <string>
#include <stdexcept>
#include <iostream>
using namespace std;
template<class EX>
class traced_error : virtual public std::exception, virtual public EX
{
public:
traced_error(const std::string& file, int line, const EX& ex)
: EX(ex),
line_(line),
file_(file)
{
}
const char* what() const
{
std::stringstream ss;
static std::string msg;
ss << "File: " << file_ << " Line: " << line_ << " Error: " << EX::what();
msg = ss.str().c_str();
return msg.c_str();
}
int line_;
std::string file_;
};
template<class EX> traced_error<EX> make_traced_error(const std::string& file, int line, const EX& ex)
{
return traced_error<EX>(file, line, ex);
}
class my_exception : virtual public std::exception
{
public:
my_exception() {};
const char* what() const
{
return "my_exception's what";
}
};
#define throwx(EX) (throw make_traced_error(__FILE__,__LINE__,EX))
int main()
{
try
{
throwx(my_exception());
}
catch( const std::exception& ex )
{
cout << ex.what();
}
return 0;
}
這個程序的輸出是:
文件:.\\main.cpp 行:57 錯誤:my_exception 是什么
您還可以重新設計它,以便應用程序級異常從traced_error
派生,而不是相反,以防您更願意捕獲特定的應用程序級異常。 在您的catch
,您可以將錯誤記錄到日志文件並使用MiniDumpWriteDump()創建轉儲文件。
您可以使用MiniDumpWriteDump函數寫入轉儲。
如果您使用的是 C++ 異常,那么您可以簡單地在拋出該異常的任何地方(使用____FUNCTION____、____FILE____ 和 ____LINE____ 宏)。
如果您試圖捕獲操作系統異常,那么使應用程序崩潰可能是更好的選擇。
您需要的是分析堆棧以找出異常的來源。 對於 msvc,有一個名為dbghelp.dll的庫可以幫助您注銷異常。 一般來說,我所做的是注銷一個小型轉儲文件,並使用它來重播問題,同時使用正確的程序數據庫(pdb 文件)。 這適用於不附帶源代碼或您不想向其提供 pdbs 的客戶系統。
與編譯器無關的一個技巧是將 throw 語句包裝在一個函數中。 該函數可以在拋出異常之前執行其他任務,例如記錄到日志文件。 它還可以方便地放置斷點。 如果您創建一個宏來調用該函數,您可以自動包含發生拋出的__FILE__
和__LINE__
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.