C + + 风格的演员阵容对性能的影响?

我是 C + + 风格强制类型转换的新手,我是 担心使用 C + + 风格强制转换会破坏我的应用程序的性能,因为在我的中断服务例程中有一个 实时关键的最后期限

我听说有些强制类型甚至会抛出异常!

我想使用 C + + 风格的强制转换,因为它会使我的代码更加“健壮”。然而,如果有任何性能的打击可能不会使用 C + + 风格的强制转换,而是会花费更多的时间来测试使用 C 风格强制转换的代码。


有人做过严格的测试/分析来比较 C + + 风格类型转换和 C 风格类型转换的性能吗?

你的结果是什么?

你得出了什么结论?

50187 次浏览

唯一一个在运行时有额外成本的是 dynamic_cast,它的功能无论如何都不能用 C 风格的强制转换直接复制。所以你没有问题。

让自己放心的最简单的方法是指示编译器生成汇编程序输出,并检查它生成的代码。例如,在任何理智实现的编译器中,reinterpret_cast将完全消失,因为它只意味着“盲目地假装数据是这种类型”。

如果 C + + 风格的强制转换在概念上可以被 C 风格的强制转换所取代,那么就不会有开销。如果不能,就像 dynamic_cast的情况一样,对于没有 C 等价物的情况,你必须以某种方式支付成本。

例如,以下代码:

int x;
float f = 123.456;


x = (int) f;
x = static_cast<int>(f);

用 VC + + 为两个强制转换生成相同的代码-代码如下:

00401041   fld         dword ptr [ebp-8]
00401044   call        __ftol (0040110c)
00401049   mov         dword ptr [ebp-4],eax

当转换为引用时,唯一可以抛出的 C + + 转换是 dynamic_cast。若要避免这种情况,请转换到指针,如果转换失败,该指针将返回0。

当使用 dynamic_cast时,在运行时会进行多次检查,以防止您做一些愚蠢的事情(在 海湾合作委员会邮件列表中更多) ,一个 dynamic_cast的成本取决于有多少个类受到影响,哪些类受到影响,等等。
如果你真的确定模型是安全的,你仍然可以使用 reinterpret_cast

为什么会有演出受到打击?它们执行与 C 强制转换相同的 没错功能。唯一的区别是,它们在编译时捕获更多的错误,并且在源代码中更容易搜索。

static_cast<float>(3)完全等价于 (float)3,并将生成完全相同的代码。

给定 float f = 42.0f reinterpret_cast<int*>(&f)完全等价于 (int*)&f,并将生成完全相同的代码。

诸如此类。唯一不同的强制转换是 dynamic_cast,它可以抛出异常。但这是因为它做到了 C 风格的演员不能做的事情。因此,除非您需要 dynamic_cast的功能,否则不要使用它。

假设编译器编写器是智能的通常是安全的。给定两个根据标准具有相同语义的不同表达式,通常可以安全地假设它们将在编译器中实现相同。

Oops : 第二个示例应该是 rerelease _ cast,当然不是 Dynamic _ cast。

好吧,让我们把话说清楚,C + + 标准是这么说的:

5.4.5:

执行的转换

  • A const_cast(5.2.11)
  • A static_cast(5.2.9)
  • 一个 static_cast后面跟着一个 const_cast
  • (5.2.10) ,或
  • 一个 reinterpret_cast后面跟着一个 const_cast

可以使用强制转换执行 显式类型转换符号。 相同的语义限制和 行为适用。如果转换可以 解释 以上列出的方法,解释 第一个出现在列表中的是 使用,即使是由于 这种解释是错误的。

因此,如果是 什么都行,由于 C 风格的强制转换是根据 C + + 强制转换实现的,所以 C 风格的强制转换应该是 慢一点。(当然不是这样,因为编译器在任何情况下都会生成相同的代码,但是这比 C + + 风格的转换速度更慢更合理。)

虽然我同意“在运行时唯一有额外成本的是 dynamic_cast”的说法,但是请记住,可能存在特定于编译器的差异。

我已经看到了一些针对我当前编译器的 bug,其中代码生成或优化略有不同,这取决于您使用的是 C 风格还是 C + + 风格的 static_cast强制转换。

所以如果你担心,检查热点的拆卸。否则,只需在不需要动态强制转换时避免它们。(如果关闭 RTTI,则无论如何都不能使用 dynamic_cast。)

有四种 C + + 风格的类型:

  • const_cast
  • static_cast
  • reinterpret_cast
  • dynamic_cast

如前所述,前三个是编译时操作。对于使用它们没有运行时惩罚。它们是向编译器发出的信息,即已声明为一种方式的数据需要以另一种方式访问。“我说这是一个 int*,但让我访问它,就像它是一个指向 sizeof(int) charchar*”或“我说这个数据是只读的,现在我需要把它传递给一个函数,这个函数不会修改它,但不会将参数作为常量引用。”

除了通过向错误类型强制转换造成的数据损坏和数据损坏(C 风格强制转换总是有可能造成的)之外,这些强制转换最常见的运行时问题是实际上声明为 const的数据可能不能转换为非常数。将声明为 const的内容转换为 non-const,然后对其进行修改是未定义的。未定义意味着你甚至不能保证会出车祸.

dynamic_cast是一个运行时构造,必须具有运行时开销。

这些强制类型转换的价值在于,它们特别说明了你试图从/到哪里进行强制类型转换,在视觉上突出,并且可以用脑死亡的工具进行搜索。我建议使用它们而不是使用 C 风格的强制类型转换。

规范的真理是组合,所以两者都试一下,看看是否得到不同的逻辑。

如果你得到完全相同的组装,没有区别-不可能有。只有在纯 C 例程和库中才真正需要坚持使用旧的 C 类型转换,在这些例程和库中,仅仅为了类型转换而引入 C + + 依赖性是没有意义的。

需要注意的一件事是,在一段相当大的代码中,到处都会发生强制转换。在我的整个职业生涯中,我从来没有在逻辑中搜索过“所有强制类型转换”——你倾向于搜索像“ A”这样的特定类型的强制类型转换,而搜索“(A)”通常和搜索“ static _ cast < A >”一样有效。使用新的强制类型转换来进行类型验证之类的事情,而不是因为它们使搜索变得无论如何都不会更容易。