首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么C++编译器不从最后一个类中优化这个dynamic_cast?

为什么C++编译器不从最后一个类中优化这个dynamic_cast?
EN

Stack Overflow用户
提问于 2017-06-11 23:16:00
回答 1查看 538关注 0票数 13

考虑一下这个类的层次结构:

代码语言:javascript
复制
struct Animal { virtual ~Animal(); };
struct Cat : virtual Animal {};
struct Dog final : virtual Animal {};

我的理解是,将final放在class Dog上可以确保没有人能够创建继承自Dog的类,这意味着没有人能够同时创建一个类-A Dog和IS-A Cat

考虑这两个dynamic_cast

代码语言:javascript
复制
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"),但是生成了对__dynamic_castto_final调用。

这真的是错过了优化机会(在编译器中,显然有人花了一些精力在强制转换中尊重final限定符),还是由于一些我还没有看到的微妙的原因而不可能进行优化?

EN

回答 1

Stack Overflow用户

发布于 2017-06-12 02:38:50

好吧,我翻了一下Clang的查找此方法的源代码

代码语言:javascript
复制
/// 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总是空的,而是因为Cat不在Dog派生的记录链中。当然,如果它没有final属性,那么它就会提前退出(就像Cat是Src时那样),但是它不一定总是空的。

我猜这有几个原因。第一种情况是,dynamic_cast在记录链上和下面都进行了转换。当Source记录具有最终属性时,您可以简单地检查链,如果Dest是祖先(因为不能从Source派生类)。

但是,如果这门课不是最后一堂课呢?我怀疑可能还有更多。也许多重继承使得查找强制转换比向下转换更困难?如果没有在调试器中停止代码,我所能做的就是推测。

我确实知道:isAlwaysNull是一个早期退出的函数。这是一个合理的断言,它试图证明结果始终为空。你不能像他们说的那样证明一个否定的,但你可以证明一个积极的。

也许您可以查看Git历史记录中的文件,并发送电子邮件给编写该函数的人。(或者至少添加了final检查)。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44489597

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档