我听说有些转换甚至会抛出异常!
我想使用C++风格的转换,因为它会使我的代码更加"健壮"。然而,如果有任何性能损失,那么我可能不会使用C++风格的转换,而是会花更多时间测试使用C风格转换的代码。
有没有人进行过严格的测试/分析,以比较C++风格的转换和C风格的转换的性能?
你的结果是什么?
你得出了什么结论?
有没有人进行过严格的测试/分析,以比较C++风格的转换和C风格的转换的性能?
你的结果是什么?
你得出了什么结论?
int x;
float f = 123.456;
x = (int) f;
x = static_cast<int>(f);
00401041 fld dword ptr [ebp-8]
00401044 call __ftol (0040110c)
00401049 mov dword ptr [ebp-4],eax
在C++中,唯一可能会抛出异常的转换操作是使用dynamic_cast
将一个对象转换成引用类型。为了避免抛出异常,可以将对象转换成指针类型,如果转换失败将返回0。
运行时唯一需要额外成本的是dynamic_cast
,因为它具有无法直接使用C风格转换实现的功能。所以你没有问题。
让自己放心的最简单方法是指示编译器生成汇编代码,并检查它所生成的代码。例如,在任何正常实现的编译器中,reinterpret_cast
将完全消失,因为它只是意味着“盲目地前进并假装数据是这种类型”。
static_cast<float>(3)
等效于 (float)3
,并且将生成完全相同的代码。float f = 42.0f
,
reinterpret_cast<int*>(&f)
等效于 (int*)&f
,并且将生成完全相同的代码。dynamic_cast
不同,它可以抛出异常。但这是因为它执行了 C 式强制类型转换不能做的事情。所以不要使用 dynamic_cast
,除非你需要它的功能。因此,如果说有什么区别的话,由于C风格的强制转换是基于C++强制转换实现的,所以C风格的转换应该会更慢一些。(当然,它们并不会慢,因为编译器在任何情况下都会生成相同的代码,但这比C++风格的强制转换较慢更可信。)
有四种C ++强制类型转换:
const_cast
static_cast
reinterpret_cast
dynamic_cast
如前所述,前三个是编译时操作。使用它们不会产生运行时惩罚。这是向编译器发送消息,表明已声明的数据需要以不同的方式访问。“我说这是一个int*
,但让我像指向sizeof(int)char
的char*
一样访问它”,或者“我说这些数据是只读的,现在我需要将其传递给一个不修改它,但不以const引用作为参数的函数。”
除了通过将类型进行错误的强制类型转换并在数据上覆盖而导致数据损坏(这始终是C风格转换的可能性)之外,这些转换最常见的运行时问题是实际上已声明为const
的数据可能无法强制转换为非常量。将声明为const
的内容转换为非const然后进行修改是未定义的。未定义意味着您甚至不能保证会崩溃。
dynamic_cast
是运行时构造,因此必须有运行时成本。
这些转换的价值在于它们明确说明您要从哪里/到哪里进行强制类型转换,外观醒目,并且可以使用智障工具进行搜索。我建议使用它们而不是使用C风格的转换。
static_cast
也可以导致运行时操作,就像 C 风格的转换一样(例如,当您将浮点数转换为整数或反之亦然时)。 - MikeMBstatic_cast
在浮点数和整数之间进行转换?你可以直接赋值:double d = 5; int i = d;
。转换可能会带来运行时成本,但即使您不编写 static_cast
,也必须支付该成本。 - Max Lybbertstatic_cast
做的不仅仅是告诉编译器以不同的方式解释位(这就是 reinterpret_cast
和 const_cast
所做的)。 - MikeMBdynamic_cast
时,运行时会进行多项检查以防止您做出愚蠢的事情(更多信息请参见GCC邮件列表),一个dynamic_cast
的成本取决于受影响的类有多少个,受影响的是哪些类等等。reinterpret_cast
。dynamic_cast
”这个说法,但请记住可能存在特定于编译器的差异。static_cast
转换而略有不同。dynamic_cast
)。规范的真相是汇编,所以尝试两种方法并查看是否得到不同的逻辑。
如果你得到完全相同的汇编代码,那么就没有区别- 不可能有区别。你唯一需要坚持使用旧的C强制转换的地方是在纯C例程和库中,在这些情况下引入C++依赖关系是没有意义的。
需要注意的一件事是,在一个相当大的代码片段中,强制转换随处可见。在我整个职业生涯中,我从来没有搜索过“所有强制转换”的逻辑- 你倾向于搜索特定类型的强制转换,比如'A',而"(A)"的搜索通常与"static_cast<A>"之类的内容一样有效。使用新的强制转换进行类型验证等操作,而不是因为它们使你永远不会执行的搜索更容易。
static_cast
和reinterpret_cast
不会总是产生相同的运行时代码,并且实际上两种转换之间有非常少的重叠。例如:您不能使用reinterpret_cast
将浮点数转换为整数(但可以从double*
转换为int*
),当您使用static_cast
进行此操作时,它不是免费的,而实际上需要执行一个或多个指令(就像C风格的转换一样)。在类的情况下,static_cast
甚至可能调用函数。 - MikeMB