在我的代码中,我抛出了自定义的file_error异常,该异常派生自std :: runtime_error。在另一个模块中,我捕获该操作的异常,并希望像这样处理我的file_error:
try
{
base::create_directory(INVALID_NAME, 0700);
...
}
catch (const base::file_error &exc)
{
...
}
catch(std::runtime_error &exc)
{
...
}
catch(std::exception &exc)
{
...
}
file_error声明为:
namespace base {
class file_error : public std::runtime_error
{
int sys_error_code;
public:
file_error(const std::string &text, int err);
error_code code();
int sys_code();
};
}
但是,永远不会触发file_error的catch分支。要么我最终都在runtime_error分支中,要么我将其删除,在异常分支中。
然而,这在Linux + Win(gcc,VS)中运行良好,而在Mac(clang)上不起作用。知道这里有什么不对吗?
更新
当我到达runtime_error分支时,这里是lldb输出:
(lldb) p exc
(const base::file_error) $0 = {
std::runtime_error = {
__imp_ = (__imp_ = 0x0000000000000000)
}
sys_error_code = 13923331
}
这清楚地表明异常确实是base :: file_error类型。它只是没有陷入相关的陷阱。
更新2:
在与上述测试代码相同的文件中基于file_error声明自己的错误,如下所示:
class test_error : base::file_error {
public:
test_error(const std::string &s) : base::file_error(s, 0) {};
};
允许我在test_error块和catch-all块中捕获它,但不能在base :: file_error,std :: runtime_error或std :: exception块中捕获它。怪异。
更新3:
经过大量的实验后,我现在认为这是一个类型不匹配问题,类似于ODR违规但是另一种类型。 dylib和测试应用程序中的类型不被认为是相同的,因此不会捕获异常,除非我在测试代码中直接抛出base :: file_error exeption。
答案 0 :(得分:4)
class test_error : base::file_error
允许我在test_error块和catch-all块中捕获它,但不能在base :: file_error,std :: runtime_error或std :: exception块中捕获它。
您的异常类需要从基本异常类派生公开。否则你将无法通过基类捕获它们:
class test_error : public base::file_error
答案 1 :(得分:1)
此问题的解决方案是避免在测试应用程序中使用编译器选项-fvisibility=hidden
(或使其成为默认值)。在这里阅读更多相关信息:https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#Code-Gen-Options。特别是这部分:
请注意,-fvisibility确实会影响C ++模糊链接实体。这个 例如,意味着抛出异常类 DSO必须明确标记为默认可见性,以便 'type_info'节点在DSO之间统一。
这些技术的概述,它们的好处以及如何使用它们 在http://gcc.gnu.org/wiki/Visibility。