为什么C++编译器不从最终类优化此dynamic_cast?
Why don't C++ compilers optimize this dynamic_cast from a final class?
考虑这个类层次结构:
struct Animal { virtual ~Animal(); };
struct Cat : virtual Animal {};
struct Dog final : virtual Animal {};
我的理解是,final
放在class Dog
上可以确保没有人可以创建继承自Dog
的类,这意味着没有人可以创建IS-A同时Dog
和IS-ACat
的类。
考虑以下两个dynamic_cast
:
Dog *to_final(Cat *c) {
return dynamic_cast<Dog*>(c);
}
Cat *from_final(Dog *d) {
return dynamic_cast<Cat*>(d);
}
GCC、ICC和MSVC忽略了final
限定符并生成__dynamic_cast
调用;这是不幸的,但并不奇怪。
令我惊讶的是,Clang和Zapcc都为from_final
生成了最佳代码("始终返回nullptr"),但生成了对to_final
__dynamic_cast
的调用。
这真的是一个错失的优化机会(在编译器中,显然有人付出了一些努力来尊重强制转换中的final
限定符),还是在这种情况下由于一些我仍然没有看到的微妙原因而无法进行优化?
好的,我翻遍了 Clang 的源代码来找到这个方法:
/// isAlwaysNull - Return whether the result of the dynamic_cast is proven
/// to always be null. For example:
///
/// struct A { };
/// struct B final : A { };
/// struct C { };
///
/// C *f(B* b) { return dynamic_cast<C*>(b); }
bool CXXDynamicCastExpr::isAlwaysNull() const
{
QualType SrcType = getSubExpr()->getType();
QualType DestType = getType();
if (const PointerType *SrcPTy = SrcType->getAs<PointerType>()) {
SrcType = SrcPTy->getPointeeType();
DestType = DestType->castAs<PointerType>()->getPointeeType();
}
if (DestType->isVoidType()) // always allow cast to void*
return false;
const CXXRecordDecl *SrcRD =
cast<CXXRecordDecl>(SrcType->castAs<RecordType>()->getDecl());
//********************************************************************
if (!SrcRD->hasAttr<FinalAttr>()) // here we check for Final Attribute
return false; // returns false for Cat
//********************************************************************
const CXXRecordDecl *DestRD =
cast<CXXRecordDecl>(DestType->castAs<RecordType>()->getDecl());
return !DestRD->isDerivedFrom(SrcRD); // search ancestor types
}
我对解析代码有点厌倦了,但在我看来,您的from_final
并非因为 Final 属性而总是 null,而是因为该Cat
不在派生Dog
记录链中。 当然,如果它没有final
属性,那么它会提前退出(就像Cat
是 Src 时一样),但它不一定总是 null。
我猜这有几个原因。 首先是dynamic_cast在唱片链上上下下投射。 当源记录具有最终属性时,您只需检查链是否 Dest 是祖先(因为不能有来自源的派生类)。
但是,如果课程不是最终课程怎么办?我怀疑可能还有更多。 也许多重继承使搜索向上的演员比向下的演员更困难? 在不停止调试器中的代码的情况下,我所能做的就是推测。
我知道这一点:isAlwaysNull
是一个早期退出功能。 这是一个合理的断言,它试图证明结果总是空的。 你不能证明一个否定(正如他们所说),但你可以反驳一个积极的。
也许你可以检查文件的 Git 历史记录,并通过电子邮件发送给编写该函数的人。(或至少添加了final
检查)。
- 空基优化子对象的地址
- 关闭||运算符优化
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 返回值优化:显式移动还是隐式
- 人脸跟踪arduino代码的优化
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 纯函数,为什么没有优化
- 为什么大多数 pair 实现默认不使用压缩(空基优化)?
- 如何以优化的方式同时迭代两个间距不相等的数组
- 小字符串优化(调试与发布模式)
- 浮点定向舍入和优化
- Visual Studio 调试优化如何工作?
- 在成员dynamic_bitset上使用 boost::from_block_range 时出错,但在本地dynamic
- 为什么开关的优化方式与 c/c++ 中的链接不同?
- 线性优化目标函数中的绝对值
- GCC 会优化内联访问器吗?
- gcc 如何优化此循环?
- 如何防止 CUDA-GDB 中的<优化输出>值
- 为什么我的程序在 O0 和 O2 的优化级别返回不同的结果
- 这个C++编译器优化(在自身的实例上调用对象自己的构造函数)的名称是什么,它是如何工作的?