【问题标题】:Automatic selection between static_cast and dynamic_cast for best performance在 static_cast 和 dynamic_cast 之间自动选择以获得最佳性能
【发布时间】:2021-06-18 14:17:59
【问题描述】:

我必须使用一个对象工厂来创建几​​种类型的新对象,每种类型都派生自多态基类。每个对象的类型都是事先知道的,但工厂返回基类上的指针。因此,在构造之后,我需要将该指针向下转换为特定对象类的类型。在大多数情况下static_cast 完美地完成了它的工作,但在虚拟继承的情况下dynamic_cast 必须用于向下转换。同时,由于运行时开销,我不想将dynamic_cast 用于从基类非虚拟继承的简单类型。

换句话说,我想找到或制作一个函数,如果它可用于此转换(例如,To 不是 实际上派生自From) 或dynamic_cast,否则。

预期用例:

template <typename To, typename From>
To fastest_cast( From && from );

struct A { virtual ~A() = default; };
struct B : A {};
struct C : virtual A {};

int main()
{
    B b;
    fastest_cast<B*>( (A*)&b ); //expected static_cast inside

    C c;
    fastest_cast<C*>( (A*)&c ); //expected dynamic_cast inside
}

在 std-library 或 boost-library 中是否有类似于 fastest_cast 的内容?还是需要自己实现转换功能(请指教)?

【问题讨论】:

  • 这是一个有效的问题,可能有办法。但同样值得注意的是,如果您出于性能原因这样做,则可能会被误导。您正在牺牲dynamic_cast(即运行时检查)的安全性来换取跳过它的感知效率。而且,在我看来,如果您非常担心转换类型的效率问题,那么您可能一开始就不应该在程序的那部分使用虚拟继承。
  • 这不是降神会。 static_cast 在代码中说:我知道它是什么类型,只是在编译时进行转换。 dynamic_cast 说:我怀疑这种类型会在运行时检查它。如果您需要这个奇怪的fastest_cast,您不了解差异,或者您在代码中做了一些奇怪的事情。
  • 我不确定您为什么希望在第一种情况下使用 static_cast。不能保证 A*B*,它可能是从 A 派生的其他类。
  • 编译器可能已经优化了这个给定的静态分析。这应该很容易在 Godbolt godbolt.org 上验证
  • A* 转换为C* 时,static_cast 表达式的格式明显不正确。 SFINAE 对此并不难。也可以在调试和发布模式下使其行为不同。如果您有良好的测试覆盖率,这可能不是一个毫无意义的冒险。

标签: c++ dynamic-cast static-cast virtual-inheritance


【解决方案1】:

std::derived_from 的概念似乎涵盖了你想要static_cast 的情况,我们只需要删除它的引用或指针。

template <typename To, typename From>
concept castable = (std::is_pointer_v<To> && std::is_pointer_v<std::remove_cvref_t<From>>) || (std::is_reference_v<To>)

template <typename From, typename To>
concept castable_from = std::derived_from<From, std::remove_cv_t<std::remove_pointer_t<To>>> || std::derived_from<From, std::remove_cvref_t<To>>

template <typename To, castable_from<To> From>
To fastest_cast(From&& from) requires castable<To, From>
{
    return static_cast<To>(from);
}

template <typename To, typename From>
To fastest_cast(From&& from) requires castable<To, From>
{
    return dynamic_cast<To>(from);
}

【讨论】:

  • 这如何解决虚拟继承问题?
  • 编译器实现没有做这个优化是有原因的吗?感觉有点像人们编写像“a a * 4 快”。除非我有充分的理由,否则我不会再猜测编译器。
  • (作为记录,我赞成有启发性的答案 - 无论问题的价值如何,该技术都是有见地的)
  • @sehe 因为static_cast 在这里不安全。如果你弄错了就是UB
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-07
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
  • 2011-06-06
  • 2011-01-16
相关资源
最近更新 更多