无法捕获自定义 std::runtime_error
Cannot catch custom std::runtime_error
在我的代码中,我抛出了自定义 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) [=13=] = {
std::runtime_error = {
__imp_ = (__imp_ = 0x0000000000000000)
}
sys_error_code = 13923331
}
这清楚地表明异常确实是 base::file_error 类型。它只是没有在其关联的 catch 块中被捕获。
更新二:
在与上面的测试代码相同的文件中声明基于 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 异常。
class test_error : base::file_error
allows me to catch it in a test_error block and in a catch-all block, but not in base::file_error, std::runtime_error or std::exception blocks.
您的异常 classes 需要 publicly 从基本异常 classes 派生。否则你将无法通过基地 class:
捕捉到它们
class test_error : public base::file_error
此问题的解决方案是避免在测试应用程序中使用编译器选项-fvisibility=hidden
(或将其设为默认值)。在此处阅读更多相关信息:https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#Code-Gen-Options。特别是这部分:
Note that -fvisibility does affect C++ vague linkage entities. This
means that, for instance, an exception class that is be thrown between
DSOs must be explicitly marked with default visibility so that the
‘type_info’ nodes are unified between the DSOs.
An overview of these techniques, their benefits and how to use them is
at http://gcc.gnu.org/wiki/Visibility.
在我的代码中,我抛出了自定义 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) [=13=] = {
std::runtime_error = {
__imp_ = (__imp_ = 0x0000000000000000)
}
sys_error_code = 13923331
}
这清楚地表明异常确实是 base::file_error 类型。它只是没有在其关联的 catch 块中被捕获。
更新二:
在与上面的测试代码相同的文件中声明基于 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 异常。
class test_error : base::file_error
allows me to catch it in a test_error block and in a catch-all block, but not in base::file_error, std::runtime_error or std::exception blocks.
您的异常 classes 需要 publicly 从基本异常 classes 派生。否则你将无法通过基地 class:
捕捉到它们class test_error : public base::file_error
此问题的解决方案是避免在测试应用程序中使用编译器选项-fvisibility=hidden
(或将其设为默认值)。在此处阅读更多相关信息:https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#Code-Gen-Options。特别是这部分:
Note that -fvisibility does affect C++ vague linkage entities. This means that, for instance, an exception class that is be thrown between DSOs must be explicitly marked with default visibility so that the ‘type_info’ nodes are unified between the DSOs.
An overview of these techniques, their benefits and how to use them is at http://gcc.gnu.org/wiki/Visibility.