【问题标题】:dynamic_cast fails - depending on OS Versiondynamic_cast 失败 - 取决于操作系统版本
【发布时间】:2015-01-10 16:03:54
【问题描述】:

我有一个失败的动态演员表。类布局是这样的:

class A1
{
    public:
virtual int foo1()=0;
};

class A2
{
    public:
    virtual int foo2();
};

class A3
{
public:
   virtual int foo3();
};

class B : public A1, public A2, public A3 
{
   int bar();
};

现在我使用指针(因此不会发生切片)进行向下转换。

main()
{
   B b;

   A1* a1 = dynamic_cast<A1*> (&b); // ok
   B*  b1 = dynamic_cast<B*>  (a1); // ok

   A2* a2_1 = dynamic_cast<A2*> (a1); // OSX 10.7 ok, OSX 10.9 fail
   A2* a1_2 = dynamic_cast<A2*> (b1); // ok

};

downcast 有效,upcast 有效,但 sidecast 并不总是有效。在 OSX 10.7 下,sidecast 工作,在 OSX 10.9 下它不工作(GCC 4.2 使用动态 c++ stdlib)。使用 gdb 查看 vtable,我可以清楚地看到列出的 A2 方法和成员。

我的问题:

a) 边播在技术上是否正确?它应该工作还是这是一个运行时错误?
b) 如果边播依赖于运行时,这个运行时在哪里定义?我一直认为这是二进制文件的一部分?
c) 失败的 dynamic_cast 是什么样子的(在查看程序集时),您如何追踪此类问题?

更新:这是我在系统控制台中看到的

11/01/15 14:16:27,435 APPNAMECHANGED[15280]:dynamic_cast 错误 1:以下两个 type_info 都应该具有公开可见性。其中至少有一个是隐藏的。 10A1,15A2。

所以 c) 得到了回答,至少对于 OSX 10.9。看看控制台。 (Linux,有人吗?) 这看起来像是关于符号可见性的问题。文档说 (gcc.gnu.org/wiki/Visibility)

然而,这还不是全部——它变得越来越难。默认情况下,符号可见性是“默认”的,但如果链接器只遇到一个隐藏的定义 - 只有一个 - 则 typeinfo 符号将永久隐藏(请记住 C++ 标准的 ODR - 一个定义规则)。这适用于所有符号,但更有可能通过 typeinfos 影响您;没有 vtable 的类的 typeinfo 符号是在每个使用 EH 类的目标文件中按需定义的,并且定义较弱,因此定义在链接时合并为一个副本。

这就引出了下一个问题,

d) 我们如何追踪哪个符号至少被标记为隐藏一次,以及在哪里以及为什么?是否有检查 .o 文件的工具?

【问题讨论】:

  • 您是否收到编译时或运行时错误,如果有,它是什么样的?
  • A1 是纯虚拟的,而 foo1 从未实现。您不能创建 B. Typo 吗?
  • FWIW——sidecast 在 Linux 上与 gcc 4.9.2 一起工作得很好。这纯粹是一个编译器问题,我不希望操作系统/平台以任何方式成为一个因素。 gcc 4.2 是古老的,我不会在它上面浪费任何时间。升级到当前的 gcc,然后收工。如果您需要解决方法,请尝试向下转换为基类,然后向上转换。
  • @Michael,sidecast 只会导致 0x0,没有异常等。
  • @tux3 我简化了案例,当然类已经实现并且工作正常

标签: c++ macos gcc4


【解决方案1】:

免责声明:我只会解决问题 a)。

首先,B 显然是根据 [class.virtual]/1 的多态类型,因为它继承了一个虚函数(准确地说,B 继承了三个不同的)。
现在考虑 [expr.dynamic.cast]/8:

如果CT 指向或引用的类类型,则运行时 check 逻辑执行如下:

  • 如果在 v 指向(引用)的最派生对象中,v 指向(引用)公共基类 C 对象的子对象,并且如果只有一个 C 类型的对象派生自指向的子对象(引用) 通过v,结果指向(指)C 对象。
  • 否则,如果v 指向(引用)最派生对象的公共基类子对象,以及最派生对象的类型 有一个C 类型的基类,它是明确且公开的, 结果指向(指)最派生的C 子对象 对象。
  • 否则,运行时检查失败

所以是的,它应该可以工作。

【讨论】:

    【解决方案2】:

    在我们发现可执行文件链接到 dylib 后,这个问题终于得到解决,dylib 本身静态链接到 c++ 运行时,但使用不同的编译器(gcc 4.8 与 clang)编译。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-29
      • 2018-03-23
      • 2015-08-26
      • 1970-01-01
      • 2012-02-05
      • 2020-09-15
      • 2012-07-22
      • 2015-02-02
      相关资源
      最近更新 更多