c++ - 在 Clang/MacOS X 上捕获派生异常类型失败

标签 c++ macos clang porting

我有一个 C++ 库,我试图用 Clang 在 Mac OS X 上运行它。该库由一个 DLL 和一个单元测试可执行文件组成。它使用 GCC 和 MSVC 编译得很好,使用 GCC,我使用以下设置:

  • 库是用-fvisibility=hidden编译的
  • 所有公开的类都明确标记为 __attribute__(visibility("default"))
  • 该库有一些异常类,派生自 std::runtime_error。所有此类类都标记为默认可见性。有一个根类 LibraryException,从中派生出更具体的异常。
  • 在 GCC 上,我使用 -std=c++0x,使用 clang,库和单元测试可执行文件都是使用 -stdlib=libc++ -std=c++ 构建的11

在 Mac OS X 上,单元测试框架现在失败了,因为异常类型错误。 IE。这样的测试失败了:

// bla.foo () throws CustomException, which is derived from LibraryException
TEST_THROWS (bla.foo (), CustomException)

// This works however
TEST_THROWS (bla.foo (), LibraryException)

我使用 nm -g library.dylib | 验证了我的自定义异常类的 typeinfo 和 vtable 是导出的 | c++filt -p -i。这似乎是所有异常(exception)情况的情况……这到底是怎么回事?我尝试调试错误,我看到了如何在库中抛出正确的类型,但无法在单元测试可执行文件中捕获相同的类型。 Clang 是否需要一些特殊的东西才能使它正常工作?我正在使用来自 SVN 的最新 googletest 框架进行测试。

一个小的测试程序表现出同样的问题:

try {
    funcThatThrowsCustomExceptionFromLibraryDylib ();
} catch (CustomException& e) {
    // doesn't get here
} catch (LibraryException& e) {
    // does get here
    // after demangle, this prints CustomException
    // Can cast down to CustomException and access the fields as well
    std::cout << typeid (e).name () << "\n";
}

例如,当从库中抛出 boost::lexical_cast 异常时,它也会失败。

最佳答案

正确的解决方法是:

在应用可见性属性时,必须在编译库时以及在使用库时应用它。否则,客户端将看不到这些类。对于 boost::lexical_cast,这意味着您必须使用

 #pragma GCC visibility push(default)
 #include <boost/lexical_cast.hpp>
 #pragma GCC visibility pop

直到他们通过向异常添加 __attribute((visibility("default"))) 将其固定在库中(从 Boost 1.50 开始,该属性存在,但似乎目前还没有对 Clang 的支持)。在库中的 header 中使用它时,可以在客户端代码中正确捕获它。此 #pragma 也适用于 Clang。

指定 throw () 析构函数这一事实是有点运气,但这绝对不是正确的解决方法。

关于c++ - 在 Clang/MacOS X 上捕获派生异常类型失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11913151/

相关文章:

java - TinyOS:RssiDemo

c++ - 关于C++中的随机数

c++ - Xlib - 窗口未渲染

macos - 从 getectbyname 读取字节时发生崩溃

clang - 用 clang 构建一个解析器

c++ - bcc32 和 bcc32c 对象生命周期的区别

c++ - AMQP-CPP > 处理程序中的错误文件描述符

c++ - 在仅在某些情况下使用 decltype 的模板中实例化函数定义

python - 我想获得 Python 的 dpkt 模块,但我不知道。我需要拦截来自 vpn 的流量

macos - OSX - ZSH - 路径 -/usr/bin 重复