【问题标题】:Is LLVM an exception to the rule for avoiding dynamic casts?LLVM 是避免动态转换规则的例外吗?
【发布时间】:2009-10-23 00:53:28
【问题描述】:

LLVM 有它自己的手动替代 RTTI,它比内置 RTTI 提高了速度,并允许动态转换为没有 vtable 的类 (dyn_cast)。但是,它仍然可以完全按照 dynamic_cast<> 的使用方式使用,尽管它确实允许它与更多类一起使用。

dyn_cast<> template documentation

LLVM 是一个享有盛誉的 C++ 项目,因此这似乎与常见的说法背道而驰,即过多的动态转换是糟糕设计的标志,也称为代码异味。与标准的dynamic_cast 相比,性能更好的动态转换肯定不会改善其在设计中的使用。那么谁在这里呢?是否存在大规模使用动态转换是 C++ 代码中一个不错的设计选择的情况? Google 在 LLVM 主干源代码中出现了 690 次这种动态转换。

Uses of dyn_cast<> in LLVM trunk

【问题讨论】:

  • 我认为它只是表明“有时,在大型软件项目中,您必须改变一些规则”。或者也许“编译器或与编译器相关的框架必须使用通常是坏主意的低级技巧”。这并不意味着我们可以就dynamic_cast的使用得出任何结论一般
  • 这似乎完全无视“规则”。我不会称 690 次事件违反规则。我看不出编译器或与编译器相关的框架有什么特别之处,这意味着它们可以打破设计信念。这里的动态转换对编译器的输出代码或输入代码没有影响,它只是设计的一部分。我可以继续你的论点,说任何足够大或足够复杂的软件都可以无视设计规则,这严重质疑这种设计建议以避免dynamic_cast

标签: c++ design-patterns llvm dynamic-cast


【解决方案1】:

虽然对于大型类层次结构,性能命中是避免 dynamic_cast<> 的一个原因,但这并不是您想要避免它们的唯一原因。无论性能是否更好,不应该因为这种说法而更鼓励使用dyn_cast<>

另一方面,当 dynamic_cast<> 是工作的最佳工具时,它绝对没有错。如果它的使用是合理的,并且是解决问题的最干净的方法,那么它总是正确的,不管“俗语”如何。

我当然不会因为流行项目使用dynamic_cast<>s、gotos 或任何其他不受欢迎的成语而避开它们。

【讨论】:

  • 当然,我认为这是一个很棒的项目,所以这是否意味着我们应该不那么认真地注意建议以避开dynamic_cast<>
  • 不,您在使用它们时应该牢记建议,并思考“这是最好的方法吗?”
【解决方案2】:

我认为动态转换不好不是因为它们很慢,而是因为它们暗示你的代码耦合太紧密了。

【讨论】:

  • 不过,它们也很慢。对我们来说大约是 1 微秒。
  • @Crashworks - 继承层次结构有多深?我相信 GCC 对 dynamic_cast 的实现在深度上是 O(n),这对某些系统来说可能非常糟糕。
  • 我认为在我测试的情况下大约是6-8个级别。整个应用程序实际上有数千个课程。
  • 我同意,你是在暗示 LLVM 耦合太紧,因此不是一个好的设计吗?
【解决方案3】:

我只是快速浏览了 LLVM 文档中 dyn_cast 和 isa 的实现。

代码中的示例如下:

struct bar {
  bar() {}
private:
  bar(const bar &);

};
struct foo {
  void ext() const;
  /*  static bool classof(const bar *X) {
    cerr << "Classof: " << X << "\n";
    return true;
    }*/
};

template <> inline bool isa_impl<foo,bar>(const bar &Val) {
  errs() << "Classof: " << &Val << "\n";
  return true;
}

使用B 调用测试并具有:

if (!isa<foo>(B1)) return;
if (!isa<foo>(B2)) return;

如果我正确理解发生了什么,isa 模板(由dyn_cast 使用)使用isa_impl 的显式特化来链接 bar 和 foo。在给出的示例中,isa&lt;foo&gt;(B1) 似乎返回 true!

无论如何,这与 dynamic_cast 的行为非常不同,所以我真的不认为你可以将它们相互比较。

显然,我可能误解了 LLVM 在做什么,所以如果我没有理解代码,请告诉我!

【讨论】:

  • 直接来自文档: dyn_cast 运算符是“检查强制转换”操作。它检查操作数是否为指定类型,如果是,则返回指向它的指针(此运算符不适用于引用)。如果操作数的类型不正确,则返回空指针。因此,它的工作原理与 C++ 中的 dynamic_cast 运算符非常相似,并且应该在相同的情况下使用。所以我不明白为什么你不能比较 dynamic_cast 和 dyn_cast。在您的示例中,我看不到 B1 和 B2 来自哪里。
  • 上面的代码来自问题中提到的页面的链接。这是他们的(即 LLVM 的)代码。这是直接链接:llvm.org/doxygen/Casting_8h-source.html。 B1 和 B2 来自该页面下方的示例。我刚刚从他们的标题中剪切并粘贴了代码。顺便说一句,您在这里粘贴的任何内容实际上都没有说明动态演员是如何发生的。它只是说它是一个类似于 dynamic_cast 的“检查演员表”。
  • 我认为实施并不会真正影响我在这里提出的问题。逐字文档中的关键引述是“因此,这与 C++ 中的 dynamic_cast 运算符非常相似,应该在相同的情况下使用。”
  • 实施对您的问题非常重要。您的问题特别询问是否可以使用 LLVM 版本的 dynamic_cast,因为它没有 dynamic_Cast 的开销。我的回答是,根据我对代码的阅读,LLVM 提供的功能与 dynamic_cast 略有不同。我对库的了解不够,无法准确地告诉您有什么区别 - 但您需要在全部替换之前让自己意识到这些区别!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-11
  • 2021-12-22
  • 1970-01-01
  • 1970-01-01
  • 2022-01-25
  • 1970-01-01
  • 2019-10-07
相关资源
最近更新 更多