你不能重載throw操作符。更常見的解決方案是定義一個宏,該宏用回溯記錄打包異常。例如這樣的:
#include <string>
#include <iostream>
#include <sstream>
#include <exception>
#include <stdexcept>
#include <type_traits>
template <typename BaseException>
class backtraced_exception : public BaseException {
private:
std::string backtrace;
public:
template <typename... Args>
backtraced_exception(const char* aFilename, int aLineNum, Args&&... args) :
BaseException(std::forward<Args>(args)...) {
std::stringstream ss;
ss << "From '" << aFilename << "' at line " << aLineNum << ":\n"
<< BaseException::what();
backtrace = ss.str();
};
backtraced_exception(const std::exception& e, const char* aFilename, int aLineNum) :
BaseException(static_cast<const BaseException&>(e)) {
std::stringstream ss;
ss << "From '" << aFilename << "' at line " << aLineNum << ":\n"
<< e.what();
backtrace = ss.str();
};
virtual ~backtraced_exception() noexcept { };
virtual const char* what() const noexcept {
return backtrace.c_str();
};
};
#define THROW_WITH_BACKTRACE(EXCEPTION, ARG1) throw backtraced_exception<EXCEPTION>(__FILE__, __LINE__, ARG1)
// ... and you can create more macros for more arguments...
#define CATCH_WITH_BACKTRACE(EXCEPTION, EXCEPT_NAME) catch(backtraced_exception<EXCEPTION>& EXCEPT_NAME)
#define RETHROW_WITH_BACKTRACE(EXCEPT_NAME) throw backtraced_exception< std::decay< decltype(EXCEPT_NAME) >::type >(EXCEPT_NAME, __FILE__, __LINE__)
使用方法如下:
int main() {
try {
try {
try {
THROW_WITH_BACKTRACE(std::runtime_error, "This is an example!");
} CATCH_WITH_BACKTRACE(std::runtime_error, e) {
std::cout << "First caught this exception:\n" << e.what() << std::endl;
RETHROW_WITH_BACKTRACE(e);
};
} catch(std::runtime_error& e) { // can also catch normally.
std::cout << "Got this exception:\n"
<< e.what() << std::endl;
// and even rethrow again, with backtrace:
RETHROW_WITH_BACKTRACE(e);
};
} catch(std::runtime_error& e) {
std::cout << "Finally, got this exception:\n"
<< e.what() << std::endl;
};
};
輸出如下:
First caught this exception:
From 'logged_except.cpp' at line 50:
This is an example!
Got this exception:
From 'logged_except.cpp' at line 53:
From 'logged_except.cpp' at line 50:
This is an example!
Finally, got this exception:
From 'logged_except.cpp' at line 59:
From 'logged_except.cpp' at line 53:
From 'logged_except.cpp' at line 50:
This is an example!
與此解決方案的另一個好處是,你可以通過簡單地禁用回溯有條件地定義宏取決於你是否想要追溯(例如調試或發佈構建)。
上面的例子需要C++ 11的特性,但是您可能會想出一個沒有這些特性的等效解決方案(即可變參數模板,decltype,類型特徵等)。
而且您還可以使用C++ 11異常指針使此方案更加方便。
你是否負責拋出這些異常?你可以從'std :: exception'派生類,在它們的構造函數中產生一個跟蹤。 –
@DrewDormann我的確是派生自'std :: runtime_error',它是'std :: exception'的子類。你能否詳細說一下'從std :: exception派生類,它們在構造函數中產生一個trace' – Chani
哪個平臺和編譯器? – Nicholaz