簡體   English   中英

獲取有關在 catch 塊內拋出 C++ 異常的位置的信息?

[英]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.

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