【问题标题】:Is reinterpret_cast any slower than a static_cast?reinterpret_cast 比 static_cast 慢吗?
【发布时间】:2016-05-28 05:18:27
【问题描述】:

我正在比较 typedef value_type 类的两个指针,它们分别是 T* 或 char16_t 类型。

编译器抱怨我无法比较这两者,因为它们是不同的类型:

'some_type1<char16_t>::value_type*' and 'some_type2<char16_t>::value_type*' lacks a cast

奇怪的是,我不能static_cast&lt;&gt; 介于两者之间:

invalid static_cast from type 'some_type1<char16_t>::value_type*' to type 'char16_t*'

无论我使用reinterpret_cast&lt;&gt; 比较还是仅使用static_cast&lt;&gt; 双方与void* 进行比较,有区别吗?

我在某处读到 reinterpret_cast&lt;&gt; 在运行时完成,但我不确定。

更新

我误以为reinterpret_cast&lt;&gt; 是在运行时完成的。经过进一步讨论,我现在明白它纯粹是一个编译时构造。

但奇怪的是,static_cast&lt;&gt; 也有运行时开销,即通过匹配构造函数将特定对象转换为另一个对象。

例如,您可以将原始int 转换为带有static_cast&lt;&gt; 的向量。这似乎适用于所有static_cast&lt;T&gt;(e) 有效的情况。

【问题讨论】:

  • 慢一点?这一切都是在编译期间完成的,你真的关心编译器完成这项工作需要多长时间吗?
  • 请edit 您的问题包含minimal reproducible example 并澄清问题。例如,以下与自身冲突; char16_t 不能等同于指针类型:它们都是 T* 或 char16_t 类型
  • 如果你不确定你应该检查Documentation。是的,它可能存在错误(我在使用它的几年中见过 2 次),但如果您不记得某些东西是如何工作的,这是一个很好的起点。
  • 当你引用char16_t的指针时,你的意思是char16_t*吗?前者是整数类型,不是指针。
  • 目前尚不清楚您要达到的目标。这两个指针完全不相关,那么将一个指针转换为另一个指针并进行比较会给您带来什么?

标签: c++ void-pointers reinterpret-cast static-cast


【解决方案1】:

我在某处读到 reinterpret_cast 在运行时完成,但我不确定。

不,那是错误的(从你得到的任何来源)。

reinterpret_cast&lt;&gt; 和 static_cast&lt;&gt; 都在编译时解析(正如您从编译器错误中看到的那样)。

static_cast&lt;&gt; 比reinterpret_cast&lt;&gt; 稍慢,因为需要在发出的代码中插入一些针对基类的偏移量计算。

您可能将这与确实在运行时完成的dynamic_cast&lt;&gt; 混淆了,并且执行速度比reinterpret_cast&lt;&gt; 或static_cast&lt;&gt; 慢一些。

【讨论】:

  • 这通过使前提无效来回答问题。我不知道我在哪里读到这个,但我找不到确认它是运行时还是编译时的来源。 static_cast 是编译时的,这可能是一个错误的假设。
  • 您的最后陈述与您的其余答案 IMO 几乎相矛盾。如何比较在两个不同范围内运行的两个元素的速度?
  • @barakmanos 动态转换不必变慢,因为它是在运行时完成的。在编译时完成的任何转换在运行时成本为 0。
  • 你不能说static_cast在运行时没有效果。确实如此。
  • @barakmanos struct A { operator B() { /* do lots of stuff here */; } }; A a; static_cast&lt;B&gt;(a); 会做事。
【解决方案2】:

即使不涉及自定义类型转换逻辑,static_cast 也可能具有(不明显的)运行时性能。这是因为在多重继承的情况下,static_cast 需要调整基数的偏移量,这需要运行时算法。虽然效果确实微乎其微,但它就在那里。从以下代码示例中可以清楚地看出:

struct Mother {
  virtual ~Mother(); 
  virtual void mother();
};

struct Father { 
  virtual ~Father();
  virtual void father();
};

struct Offspring: Mother, Father {
  void mother();
  void father();
};

void foo(Offspring* offspring) {
  Mother* mother = offspring;
  mother->mother();
}

函数foo()的ASM代码有以下一行:

movq    %rax, -8(%rbp)

这是基本偏移量。如果你移除演员表,你会看到这条线消失了。

另一方面,reinterpret_cast 真正只在编译时强制转换,在程序运行期间没有任何影响。

【讨论】:

    【解决方案3】:

    reinterpret_cast&lt;&gt; 纯粹是编译时转换。您只是在重新解释底层类型是什么,完全回避类型系统。没有可能的运行时方面。

    static_cast&lt;&gt; 可以有运行时成本,这取决于你是什么static_cast-ing。如果您正在投射 void*,或通过非多态对象层次结构,则不会产生运行时成本。如果您通过多态对象层次结构进行转换,则由于 vtable 必须在运行时发生偏移量变化。

    如果你在层次结构之外进行转换,那么你必须实际创建一个新对象。是否看起来像调用转换函数:

    struct A {
        operator B() { /* something */ }
    };
    
    A a;
    static_cast<B>(a);
    

    或转换构造函数:

    static_cast<std::vector<int>>(4);
    

    static_cast&lt;&gt; 创建了一个全新的对象 - 所以肯定需要运行一些代码来执行此操作!

    【讨论】:

    • 我不知道你可以 static_cast&lt;&gt; 原始类型到对象。它只是查看每个构造函数的兼容类型吗?
    • @Zhro static_cast&lt;T&gt;(e) 有效当且仅当 T t(e) 有效。
    • 不错。最后一条语句在将浮点实例转换为定点实例时是否也适用,反之亦然?
    • @barakmanos 你的意思是像static_cast&lt;int&gt;(2.0)?是的,那必须做某事
    • 嗯,我实际上是在考虑旧的 C 风格演员表。我一直想知道如何在运行时不实际更改操作数的“位内容”的情况下执行该转换。
    猜你喜欢
    • 2013-10-14
    • 2013-10-18
    • 2015-04-07
    • 2021-11-10
    • 2011-05-27
    • 2011-10-14
    • 2017-05-10
    • 2021-09-09
    • 2010-09-24
    相关资源
    最近更新 更多