jjzjj

c++ - RTTI 有多贵?

coder 2023-04-24 原文

我知道使用 RTTI 会造成资源损失,但影响有多大?我所看到的所有地方都只是说“RTTI 很昂贵”,但它们实际上都没有提供任何基准或定量数据来保护内存、处理器时间或速度。

那么,RTTI 到底有多贵?我可能会在只有 4MB RAM 的嵌入式系统上使用它,因此每一位都很重要。

编辑:As per S. Lott's answer ,如果我包括我实际在做的事情会更好。 I am using a class to pass in data of different lengths and that can perform different actions ,因此仅使用虚函数很难做到这一点。似乎使用一些 dynamic_cast 可以解决这个问题,允许不同的派生类通过不同的级别,但仍然允许它们完全不同的行为。

据我了解,dynamic_cast 使用 RTTI,所以我想知道在有限的系统上使用它的可行性如何。

最佳答案

不管编译器如何,如果你能负担得起,你总是可以节省运行时间

if (typeid(a) == typeid(b)) {
  B* ba = static_cast<B*>(&a);
  etc;
}

而不是

B* ba = dynamic_cast<B*>(&a);
if (ba) {
  etc;
}

前者只涉及 std::type_info 的一个比较;后者必然涉及遍历继承树和比较。

过去...就像每个人都说的那样,资源使用是特定于实现的。

我同意其他所有人的意见,即提交者出于设计原因应避免使用 RTTI。但是, 有充分的理由使用 RTTI(主要是因为 boost::any)。请记住,了解其在常见实现中的实际资源使用情况很有用。

我最近对 ​​GCC 中的 RTTI 进行了大量研究。

tl;dr: GCC 中的 RTTI 使用的空间可以忽略不计,typeid(a) == typeid(b)在许多平台(Linux、BSD 和嵌入式平台,但不是 mingw32)上非常快。如果您知道您将永远在一个有福的平台上,那么 RTTI 就非常接近免费了。

细节:

GCC 更喜欢使用特定的“供应商中立”C++ ABI[1],并且始终将此 ABI 用于 Linux 和 BSD 目标[2]。对于支持此 ABI 和弱链接的平台,typeid()为每种类型返回一个一致且唯一的对象,甚至跨越动态链接边界。可以测试&typeid(a) == &typeid(b) ,或者仅仅依靠可移植测试typeid(a) == typeid(b)实际上只是在内部比较一个指针。

在 GCC 的首选 ABI 中,类 vtable总是 持有指向每个类型 RTTI 结构的指针,尽管它可能不会被使用。所以一个typeid()调用自己应该只花费与任何其他 vtable 查找一样多的成本(与调用虚拟成员函数相同),并且 RTTI 支持不应该为每个对象使用任何额外的空间.

据我所知,GCC 使用的 RTTI 结构(这些都是 std::type_info 的所有子类)除了名称之外,每种类型只包含几个字节。即使使用 -fno-rtti,我也不清楚输出代码中是否存在名称。 .无论哪种方式,编译后的二进制文件大小的变化都应该反射(reflect)运行时内存使用的变化。

一个快速实验(在 Ubuntu 10.04 64 位上使用 GCC 4.4.3)显示 -fno-rtti实际上增加一个简单测试程序的二进制大小几百字节。这在 -g 的组合中始终如一地发生。和 -O3 .我不确定为什么尺寸会增加;一种可能性是 GCC 的 STL 代码在没有 RTTI 的情况下表现不同(因为异常不起作用)。

[1] 称为 Itanium C++ ABI,记录在 http://www.codesourcery.com/public/cxx-abi/abi.html .这些名称非常困惑:名称指的是原始开发架构,尽管 ABI 规范适用于包括 i686/x86_64 在内的许多架构。 GCC 的内部源代码和 STL 代码中的注释将 Itanium 称为"new"ABI,而不是他们之前使用的“旧”ABI。更糟糕的是,"new"/Itanium ABI 指的是通过 -fabi-version 获得的所有版本。 ; “旧” ABI 早于这个版本。 GCC 在 3.0 版本中采用了 Itanium/versioned/"new"ABI;如果我正确阅读了他们的变更日志,则在 2.95 及更早版本中使用了“旧”ABI。

[2] 我找不到任何资源列表 std::type_info平台的对象稳定性。对于我可以访问的编译器,我使用了以下内容:echo "#include <typeinfo>" | gcc -E -dM -x c++ -c - | grep GXX_MERGED_TYPEINFO_NAMES .此宏控制 operator== 的行为对于 std::type_info在 GCC 的 STL 中,从 GCC 3.0 开始。我确实发现 mingw32-gcc 遵循 Windows C++ ABI,其中 std::type_info对象对于跨 DLL 的类型不是唯一的; typeid(a) == typeid(b)来电strcmp在被子下。我推测在像 AVR 这样没有代码链接的单程序嵌入式目标上,std::type_info物体总是稳定的。

关于c++ - RTTI 有多贵?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/579887/

有关c++ - RTTI 有多贵?的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  3. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  4. ruby - 使用 Ruby,计算 n x m 数组的每一列中有多少个 true 的简单方法是什么? - 2

    给定一个nxmbool数组:[[true,true,false],[false,true,true],[false,true,true]]有什么简单的方法可以返回“该列中有多少个true?”结果应该是[1,3,2] 最佳答案 使用转置得到一个数组,其中每个子数组代表一列,然后将每一列映射到其中的true数:arr.transpose.map{|subarr|subarr.count(true)}这是一个带有inject的版本,应该在1.8.6上运行,没有任何依赖:arr.transpose.map{|subarr|subarr.in

  5. ruby - 变量赋值后的 if 语句 - 有多常见? - 2

    我最近与一位同事讨论了以下Ruby语法:value=ifa==0"foo"elsifa>42"bar"else"fizz"end我个人并没有看到太多这种逻辑,但我的同事指出,这实际上是一种相当普遍的Rubyism。我试着用谷歌搜索这个主题,但没有找到任何文章、页面或SO问题来讨论它,这让我相信这可能是一种非常实际的技术。然而,另一位同事发现语法令人困惑,而是将上面的逻辑写成这样:ifa==0value="foo"elsifa>42value="bar"elsevalue="fizz"end缺点是value=的重复声明和隐式elsenil的丢失,如果我们想使用它的话。这也感觉它与Ruby

  6. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  7. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

  8. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

    出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

  9. ruby - Ruby 中字符串运算符 + 和 << 的区别 - 2

    我是Ruby和这个网站的新手。下面两个函数是不同的,一个在函数外修改变量,一个不修改。defm1(x)x我想确保我理解正确-当调用m1时,对str的引用被复制并传递给将其视为x的函数。运算符当调用m2时,对str的引用被复制并传递给将其视为x的函数。运算符+创建一个新字符串,赋值x=x+"4"只是将x重定向到新字符串,而原始str变量保持不变。对吧?谢谢 最佳答案 String#+::str+other_str→new_strConcatenation—ReturnsanewStringcontainingother_strconc

  10. ruby - rails 3.2.2(或 3.2.1)+ Postgresql 9.1.3 + Ubuntu 11.10 连接错误 - 2

    我正在使用PostgreSQL9.1.3(x86_64-pc-linux-gnu上的PostgreSQL9.1.3,由gcc-4.6.real(Ubuntu/Linaro4.6.1-9ubuntu3)4.6.1,64位编译)和在ubuntu11.10上运行3.2.2或3.2.1。现在,我可以使用以下命令连接PostgreSQLsupostgres输入密码我可以看到postgres=#我将以下详细信息放在我的config/database.yml中并执行“railsdb”,它工作正常。开发:adapter:postgresqlencoding:utf8reconnect:falsedat

随机推荐