【问题标题】:When can compiling c++ without RTTI cause problems?什么时候在没有 RTTI 的情况下编译 c++ 会导致问题?
【发布时间】:2011-05-28 01:28:34
【问题描述】:

我正在使用 gcc 的 -fno-rtti 标志来编译我的 C++ 而没有运行时类型信息。

假设我没有使用dynamic_cast<>typeid(),有什么会导致我以后遇到问题吗?

【问题讨论】:

  • 这是一个假设性问题,还是您遇到问题并想知道禁用 RTTI 是否会导致这些问题?如果您遇到问题,您遇到了什么样的问题?
  • 我喜欢这个作为一般(假设)问题。如果标志有一些好处,并且没有使用类型信息,为什么不应该包含标志?
  • 为什么不呢?最小意外法则。有一天,有人会非常惊讶,因为使用标准语言功能会破坏构建。
  • 当我问这个问题时,我正在一个内存非常有限的环境(小型手臂系统)中编程,所以禁用 RTTI 是一个有用的收获。

标签: c++ gcc rtti


【解决方案1】:

由于您的问题是针对 GCC 的,因此您应该仔细查阅您正在使用的版本的文档。 GCC 4.5.2 的文档说明如下。从我的阅读中可以看出,如果你避免使用 dynamic_cast 和 typeid,你应该没问题。也就是说,我对 -fno-rtti 没有个人经验。也许您可能想详细说明为什么要使用 -fno-rtti。

-fno-rtti
禁用生成有关每个类的信息 C++ 使用的虚函数 运行时类型识别功能 (dynamic_casttypeid)。如果你 不要使用语言的那些部分, 你可以通过使用这个来节省一些空间 旗帜。注意异常处理 使用相同的信息,但它会 根据需要生成它。这 dynamic_cast运营商还是可以的 用于不需要的演员表 运行时类型信息,即强制转换 到void * 或明确的基础 类。

No RTTI but still virtual methods 讨论了虚函数和 RTTI 之间的关系。简短的版本是没有 RTTI 的虚函数应该没问题。

【讨论】:

  • 您只需要在真正内存受限的环境中编写时使用 -fno-rtti,例如嵌入式程序;现代手机通常有足够的内存让你不需要-fno-rtti,所以你必须使用更小的东西。
  • @Lie Ryan:Clang/LLVM 在他们的项目中禁用了 RTTI 以暂存内存,但它应该在普通计算机上运行。我承认这不是一个典型的项目:)
  • 让我担心的是,如果在某处发现 dynamic_cast,禁用 RTTI 不会导致编译错误
  • @lurscher,我刚刚检查了 g++ 4.2.1,它确实会产生错误。我收到以下错误“fnortti.cc:6: error: ‘dynamic_cast’ not allowed with -fno-rtti”。
  • 这是一个旧的评论线程,但我是来寻找背景来理解这篇论文的,stroustrup.com/OOPSLA-typeswitch-draft.pdf。论文回答了这个问题,在这些cmets中已经提到,typeid、dynamic_cast、异常处理是需要RTTI的三种情况。
【解决方案2】:

我们在没有 rtti 的情况下使用 gcc 5 年了,没有任何具体问题(不使用 dynamic_cast 或 typeid)

【讨论】:

  • 如果没有 rtti,几乎没有例外。
  • @Amos:异常与 RTTI 有何关联?
  • @VioletGiraffe 他们不是。 GCC 文档声明异常可以在没有 RTTI 的情况下工作 - 任何必要的数据都会根据需要生成。
【解决方案3】:

我很高兴发布另一个对一个非常古老的问题的答案,但我今天遇到了它,并想指出到目前为止给出的答案在所有方面都不准确。

如果您的代码使用的库本身使用 RTTI 信息,则可能会出现潜在问题。

下面的代码就是一个简单的例子:

#include <stdio.h>

// Library header
struct A     { virtual void fn(); };
struct B : A { virtual void fn(); };
void lib_fn(A* ptr);

// Library code
#ifdef LIB
void A::fn() { puts("a"); }

void B::fn() { puts("b"); }

void lib_fn(A* ptr)
  {
  if (B* b = dynamic_cast<B*>(ptr))
    puts("successful dynamic_cast");
  ptr->fn();
  }
#endif

// Application code
#ifdef APP
struct C : B
  { 
  virtual void fn()
    { puts("c"); }
  };

int main()
  {
  C obj;
  lib_fn(&obj);
  return 0;
  }
#endif

这里我们有一个提供许多类的库。它是用 RTTI 编译的,因为它在内部使用了dynamic_cast,但我们不知道这一点(我们没有阅读源代码,库文档中也没有提到)。以下命令可用于创建库:

g++ -shared -o libmodule.so -fPIC code.cpp -DLIB

我们也有我们的应用程序。我们子类化一个库类,并将 this 的一个实例传递给一个库函数。我们在没有 RTTI 的情况下编译我们的应用程序,因为我们想节省空间,而且我们不喜欢 RTTI 在我们的应用程序二进制文件中提取有关我们类名称的信息这一事实。要创建使用该库的应用程序可执行文件:

g++ -s -fno-rtti -o app code.cpp -DAPP -L. -lmodule -Wl,-rpath,.

使用-fno-rtti 编译的此应用程序将崩溃,因为该应用程序不包含 RTTI 信息,即使它本身不使用它,库也会使用它。

如果这是一个第三方库,则可能无法确定它不会以可能影响您的代码的方式使用 dynamic_cast。更糟糕的是,它可能不是今天,但它可能会在未来被替换为一个版本,此时应用程序将然后开始崩溃。

【讨论】:

    猜你喜欢
    • 2021-12-29
    • 1970-01-01
    • 2018-04-26
    • 2023-02-23
    • 2011-08-25
    • 1970-01-01
    • 2014-05-17
    • 2011-01-20
    • 2020-01-26
    相关资源
    最近更新 更多