如何在c++中编写自定义异常类时重载throw函数
How is it possible to overload the throw function while writing a custom exception class in C++?
我写了一个例程来存储回溯、行号和文件名等。这样做的目的是存储这些数据,以便在抛出异常时使用。然而,我面临的问题是,我的例程将从catch块调用,并且它最终将存储回溯到catch块。这可不太好。我只需要在抛出异常的地方添加回溯。我不能(显然在try块中调用它,因为在这种情况下,即使在没有抛出异常的情况下,我最终也会存储回溯)。我还可以总是将backtrace存储到try块的末尾,并在catch块中访问它;但是没有办法知道在try块的哪一行会抛出异常。因此,throw函数似乎是添加例程调用的好地方。但我不知道该怎么做。请帮帮我。
如果我的策略似乎是错误的,请随时给我一个更好的解决方案。如果问题本身不清楚,请留下评论。
注:我编写了自定义异常类来继承std::runtime_error。
c++中没有可以覆盖的'throw函数'。抛出是由c++实现来处理的,没有标准的方法来为每个throw
插入任何类型的代码。
相反,你可以做的是让你的异常类型在构造时存储当前的回溯。
std::string get_backtrace() {
return "this is the backtrace...";
}
struct backtrace_exception : public std::exception {
std::string b;
backtrace_exception() : b(get_backtrace()) {}
};
int main() {
try {
throw backtrace_exception();
} catch(backtrace_exception &e) {
std::cout << e.b;
}
}
不能重载抛出操作符。更常见的解决方案是定义一个宏,用回溯记录打包异常。例如:
#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、类型特征等)的等效解决方案。
是的,你可以通过重写这个函数来重写GCC下的'throw':
外来的"C"Void __cxa_throw (Void *thrown_exception, Void *pvtinfo, Void (*dest)(Void *))
在完成你的工作之后,你应该调用真正的'throw',因为你应该在Unix下使用'dlsym()'来获得它的地址,或者通过将- wl,-wrap,symbol传递给链接器来使用'mingw'下的函数包装,就像在这里GNU gcc/ld中一样-在同一个对象文件中定义调用者和被调用者来包装对symbol的调用,我使用这两种方法
- 继承函数的重载解析
- 你能重载对象变量名本身返回的内容吗
- 从父命名空间重载类型
- 使用C++中的模板和运算符重载执行矩阵运算
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 重载操作程序时出错>>用于类中的字符串 memebr
- 一个关于在C++中重载布尔运算符的问题
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- 不同翻译单元中不可重载的非内联函数定义
- 为什么使用SFINAE而不是函数重载
- 为什么我不能在 C++ 中的特定函数重载中调用同一函数的任何其他重载?
- 将重载的成员函数传递给函数模板
- c++:可变模板和函数重载
- 重载元组索引运算符-C++
- 如何使用重载的相等(==)运算符向测试用例添加描述
- 重载==不适用于二进制树
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 重载运算符new[]的行为取决于析构函数
- 正在尝试重载二进制搜索树分配运算符
- 如何在c++中编写自定义异常类时重载throw函数