【问题标题】:What is the actual purpose of std::type_info::name()?std::type_info::name() 的实际目的是什么?
【发布时间】:2015-03-04 18:10:24
【问题描述】:

今天我的一位同事来问我标题中提到的问题。
他目前正在尝试减少代码库的二进制占用空间,该代码库也用于小型目标(如 Cortex M3 等)。显然他们已经决定在打开 RTTI 的情况下进行编译(实际上是 GCC),以支持正确的异常处理。

好吧,他的主要抱怨是为什么实际上需要std::type_info::name() 来支持 RTTI,并问我是否知道一种方法来抑制生成支持这一点所需的字符串文字,或者至少缩短它们.

std::type_info::name

const char* name() const; 返回包含类型名称的实现定义的以空字符结尾的字符串。不提供任何保证,特别是返回的字符串对于多种类型可以是相同的,并且在同一程序的调用之间会发生变化。

A ,- 但是编译器特定的-,例如的实现dynamic_cast<> 运算符不会使用此信息,而是使用类似于哈希标签的东西来确定类型(类似于 catch() 具有异常处理的块)。
我认为后者在当前的标准定义中明确表达了

  1. std::type_info::hash_code
  2. std::type_index

我不得不同意,除了用于调试(记录)目的之外,我也没有真正看到使用 std::type_info::name() 的意义。我不是 100% 确定异常处理在没有 RTTI 的情况下使用当前版本的 GCC(我认为他们使用的是 4.9.1),所以我犹豫是否建议直接关闭 RTTI。
在他们的代码库中使用dynamic_casts<> 也是这种情况,但对于这些,我只是建议不要使用它,而支持static_cast (他们实际上没有插件之类的东西,或者不需要运行时类型检测除了断言)。


问题:

  • 除了日志记录之外,std::type_info::name() 是否存在真实的生产代码级用例?

子问题(更具体):

  • 有谁知道如何克服(解决)这些无用字符串文字的生成(假设它们永远不会被使用)?

  • 真的(仍然)需要 RTTI 来支持 GCC 的异常处理吗?
    (这部分现在由@Sehe's answer 很好地解决了,我已经接受了。对于代码中使用的任何异常,剩下的生成的std::type_info 实例仍然存在另一个子问题。我们很确定,这些文字永远不会在任何地方使用)


相关位:Strip unused runtime functions which bloat executable (GCC)

【问题讨论】:

  • 对于日志记录也不是很有用,因为名称可能是一个不能直接说明的名称。
  • 我怀疑任何明确标记为“实现定义”而没有最基本的平等保证的东西都应该在生产中使用,即使它是 100% 安全的。
  • @JoachimPileborg 甚至参考文档也提到了c++filt“使用gcc和clang等编译器,返回的字符串可以通过c++filt -t管道转换为human-可读的形式。”
  • @JoachimPileborg 因为它在一些实现上可能没用,你不会在any实现上使用它?
  • 关于子问题 #1:对于小型嵌入式目标,这通常是链接描述文件可以帮助您的问题域。本质上,如果文字被放置在二进制文件的特定部分中(我不确定 gcc 将它们放在哪里),您可以排除该部分。否则,您可以明确排除与模式匹配的符号名称;您也许可以设计一种方案来抑制生成的二进制文件中的文字(如果曾经使用过它们,显然会在运行时失败)。

标签: c++ c++11 gcc


【解决方案1】:

隔离这个位:

answer 是的:

-fno-rtti

禁止使用 C++ 运行时类型标识功能(dynamic_casttypeid)使用虚函数生成有关每个类的信息。如果您不使用语言的这些部分,则可以使用此标志节省一些空间。 请注意,异常处理使用相同的信息,但它会根据需要生成它dynamic_cast 运算符仍可用于不需要运行时类型信息的转换,即转换为 void * 或明确的基类。

【讨论】:

  • 是的,我的疑虑非常明确。我会接受这个答案(让我们看看我的同事明天会想出什么......)还有可能被覆盖的__verbose_terminate_handler 不再使用任何与异常相关的东西,甚至会退出std::type_info::name()支持异常中使用的类型?我敢肯定,我的同事会为了快乐而跳成三角形,并在两者之间展示一些翻筋斗:-)。
  • 如果您的目标是小型设备,则使用 --disable-libstdcxx-verbose 构建 GCC 以自动摆脱冗长的终止处理程序(及其所有 I/O 依赖项)
【解决方案2】:

除了日志记录之外,std::type_info::name() 是否存在真实的生产代码级用例?

Itanium ABI describes 如何轻松实现 operator==std::type_info 对象,以测试从 std::type_info::name() 返回的字符串的指针是否相等。

在非平面地址空间中,可能有多个相同类型的type_info 对象(例如,因为动态库已经加载了RTLD_LOCAL),operator== 的实现可能需要使用strcmp判断两种类型是否相同。

所以name() 函数用于确定两个type_info 对象是否引用相同的类型。对于实际用例的示例,通常在标准库中的至少两个地方使用,std::function<F>::target<T>()std::get_deleter<D>(const std::shared_ptr<T>&)

如果您不使用 RTTI,那么这一切都无关紧要,因为无论如何您都不会拥有任何 type_info 对象(因此在 libstdc++ 中无法使用 function::targetget_deleter 函数)。

我认为 GCC 的异常处理代码使用 type_info 对象本身的地址,而不是 name() 返回的字符串的地址,因此如果您使用异常但没有 RTTI,则不需要 name() 字符串。

【讨论】:

  • 如果type_info不一样,怎么能说类型一样呢?
  • 因为两个type_info 对象比较相等。
  • 那为什么name() 比较不相等呢?
  • 我不确定你在问什么,你能澄清一下吗?正如我上面所说的(“所以 name() 函数用于确定两个 type_info 对象是否引用相同的类型。”),如果它们比较相等,那么名称确实比较相等(通过指针相等或strcmp),所以问为什么名称不比较相等是没有意义的。 “不一样”是什么意思?
猜你喜欢
  • 2010-09-21
  • 2018-11-04
  • 1970-01-01
  • 2012-05-08
  • 2011-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多