dynamic_cast 在 clang 上无法跨模块边界工作

dynamic_cast doesn't work across module boundaries on clang

本文关键字:模块 边界 工作 cast clang dynamic      更新时间:2023-10-16

我看到一个非常奇怪的故障,与中描述的问题非常相似llvm clang编译器上的dynamic_cast失败:对于派生类型的对象,当我试图从基类型向下转换为派生类型时,dynamic_cast返回nullptr。在我的例子中,虽然typeid实际上显示了相同的动态类型。

下面是我用来验证运行时类型的调试函数。它获取一个SrcType*的指针,并尝试将其动态地转换为DstType*的指针。如果转换失败,即返回的指针为nullptr,则会打印一条错误消息。VERIFY()宏检查条件是否为真:

template<typename DstType, typename SrcType>
void CheckDynamicType( SrcType *pSrcPtr )
{
VERIFY(dynamic_cast<DstType*> (pSrcPtr) != nullptr, 
"Dynamic type cast failed. Src typeid: '", typeid(*pSrcPtr).name(), 
"' Dst typeid: '", typeid(DstType).name(), ''');
}

这是我得到的输出:

Dynamic type cast failed. Src typeid: 'N8Diligent15RefCountersImplE' Dst typeid: 'N8Diligent15RefCountersImplE'

我使用的是安卓ndk r16工具链中的clang编译器。我正在用rtti旗编译。同样的代码在gcc和msvc上运行良好。另一点信息是:如果我使用gnustl运行时构建代码,代码也可以正常工作(我不确定gnu-stl如何使用clang,但无论如何)。

更新

在花了几个小时研究这个问题后,我发现dynamic_cast在另一个模块中创建的对象上使用时会失败。由此使用clang++、-fvisibility=hidden、typeinfo和类型擦除,如果类标记为__attribute__((visibility("default"))),那么dynamic_cast应该可以工作,这样来自两个模块的typeid结构就会合并。然而,这也于事无补,我仍然看到这个问题。

如果您使用的是股票系统编译器,那么编译器的dynamic_cast不起作用的可能性几乎为零。这是测试和广泛使用的一切,从系统软件。