看看这个小片段:
struct A {
virtual ~A() { }
};
struct B { };
bool fn() {
A *volatile a = new A;
return dynamic_cast<B *>(a);
}
是否允许编译器完全删除dynamic_cast
并将dynamic_cast
转换为简单的nullptr;
?
这个问题的原因是这个answer。
注意:
假定volatile意味着编译器无法假定关于a
的任何信息,因为它是易失的。这是question的原因。
可能不允许删除dynamic_cast
的事实是程序中可能存在某个类型,该类型源自A
和B
。 / p>
答案 0 :(得分:2)
是的,当且仅当编译器可以证明调用的唯一有效结果是{{时,才可以忽略对dynamic_cast
的调用。 1}}。很简单。
棘手的部分是证明false
的唯一有效结果是dynamic_cast
。您可以证明,如果整个程序中没有可以同时继承false
和A
的类。
现在我对这部分不是很精通,但是我认为,当您创建二进制文件并在程序中具有所有类型时,只有它是可执行文件(而不是库)并且只有在程序没有时,您才能这样做。动态链接到其他库。
1)指针上的B
没有副作用,它不会抛出
答案 1 :(得分:2)
是的。 dynamic_cast
除了返回值外没有可观察到的行为。
编译器知道a
指向的静态类型。
因此,在as-if规则下,编译器可以在编译时自由评估动态转换。
事实上:
struct A { virtual ~A() {} };
struct B:A {};
bool foo() {
A* a = new A;
return dynamic_cast<B*>(a);
}
上面的动态强制转换语句也可以优化为return false;
。new
不能在没有整个程序优化的情况下被忽略,因为有人可能会使new全局运算符重载。一旦证明没有全局运算符new过载,它甚至可以优化对new A
的调用,因为既没有默认的operator new
分配内存,也没有创建A
也不破坏一个有任何明显的副作用。