C++ 编译器是否可以优化动态_丢弃?

C++ 编译器是否可以优化动态_丢弃?,c++,C++,我接触过这样的代码: dynamic_cast(p)->foo(); 这当然很糟糕,因为当dynamic_cast返回0时,您有一个未定义的行为 然后我想,它可能带来的一个可怕的惊喜是,因为当p可以转换为a*时,这与执行静态_转换是一样的,当无法获得未定义的行为时,编译器可以将动态_转换为静态_转换,并保持一致的行为。 也就是说,我使用编译器资源管理器尝试了以下代码: A类{ 虚拟空心条()=0; }; B类期末考试:公共A{ 公众: void foo(); 无效条()覆盖; }; 空h();

我接触过这样的代码:

dynamic_cast(p)->foo();
这当然很糟糕,因为当dynamic_cast返回0时,您有一个未定义的行为

然后我想,它可能带来的一个可怕的惊喜是,因为当p可以转换为a*时,这与执行静态_转换是一样的,当无法获得未定义的行为时,编译器可以将动态_转换为静态_转换,并保持一致的行为。 也就是说,我使用编译器资源管理器尝试了以下代码:

A类{
虚拟空心条()=0;
};
B类期末考试:公共A{
公众:
void foo();
无效条()覆盖;
};
空h();
空f(A*常数p)
{
动态_cast(p)->foo();
}

令我惊讶的是,每个编译器都保留了动态_cast调用。是否有什么东西让我无法理解,或者编译器根本没有进行可能的优化?

我不明白为什么不可能进行优化。编译器可以看到只有两种情况存在:

  • 操作数的动态类型为
    B
    ,因此强制转换可以是静态的
  • 操作数的动态类型是从
    A
    派生的其他类型,在这种情况下,结果是
    nullptr
    ,并且完整表达式具有未定义的行为
(由于
final
说明符,不可能从
B
派生任何类型。这很方便,因为如果可能的话,静态强制转换不一定是动态强制转换的适当替代-必须考虑多重继承和侧置转换,并且其中可能没有足够的信息链接时间优化将进一步缓解这种情况,但实际上,大多数类似的优化都发生在编译时,任何支持
dlopen
的平台也将否决这种可能性。)

所以,我们只有一个案例可以得到一个定义良好的程序

由于编译器被允许假设输入没有未定义的行为,如果删除所有导致UB的代码路径只剩下一个可能的结果,那么编译器可以假设这将始终是结果。这就是未定义行为成为一件事的核心原因,允许像这样的优化,以及MPiler会一直执行这些操作,以使您的代码简洁快速


我承认,对于主流编译器在这种情况下没有利用这个机会,我有点惊讶。我至少希望得到一个关于冗余
动态转换的警告;不过,一些静态分析器可能会给你这个提示。

看起来你希望编译器编写者这样做:。没有pr实际需要这样的优化(不过,如果有一个警告,说明动态\u cast功能的一部分没有被使用,因此可以用静态\u cast替换,那就好了).@Someprogrammerdude这就是问题所在。在您描述的例子中,完整表达式具有未定义的行为。编译器一直都以这种方式使用UB。然而,这似乎并不是他们当时利用的场景moment@ChrisMM当程序有未定义的行为时。@ChrisMM:C中的未定义行为++可以做任何事情,包括更改过去操作的结果。这允许编译器在这种特定情况下假装
dynamic_cast
没有返回空指针。或者,换句话说,允许编译器利用以下事实:在上面的示例中,实际上只有一种情况下程序运行良好-形式化,因此不需要
动态\u cast
。你可能认为这是吹毛求疵或白日做梦,但事实并非如此。这正是编译器一直在执行的优化类型。这正是UB的原因。我可以看到这种情况“无意中”发生如果编译器碰巧在内部将这两种情况表示为两个分支,并且如果优化器在一个分支中发现nullptr UB,那么泛型情况可能更常见。@MSalters确切地说,这就是可以(而且经常)进行的优化我承认我有点惊讶不是在这种情况下,但是hey@Kit.好的,是的,我想你是对的。我来调整一下。谢谢:)