【问题标题】:Cannot catch custom std::runtime_error无法捕获自定义 std::runtime_error
【发布时间】:2015-06-23 10:27:56
【问题描述】:

在我的代码中,我抛出了源自 std::runtime_error 的自定义 file_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 类型。它只是没有被其关联的 catch 块捕获。

更新 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 异常。

【问题讨论】:

  • 这可能表明您违反了 ODR:base::runtime_error 的多个定义被应用程序的不同部分使用。
  • 不,我检查了所有代码。只有一个定义存在。
  • 尝试使用带有--detect-odr-violations命令行选项的gold链接。
  • 为什么它会在调试器中显示为const,而您的异常处理程序通过引用非常量捕获异常?
  • 那只是因为我尝试了各种组合并且不想不断更新问题文本。最初的 catch 块是为(const base::file_error &exc)

标签: c++ exception exception-handling clang


【解决方案1】:
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 

【讨论】:

  • 好收获。这至少解释了为什么我无法将测试错误捕获为 file_error,它现在可以工作。只是原来的问题仍然悬而未决。
【解决方案2】:

此问题的解决方案是避免在测试应用程序中使用编译器选项-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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-22
    • 2010-12-06
    • 1970-01-01
    相关资源
    最近更新 更多