引用static_cast和指向指针static_cast的引用的开销

时间:2017-06-27 13:26:27

标签: c++ pointers reference

对引用static_cast的引用是否与指向static_cast的指针具有相同的运行时间成本?

E.g。

class B;
class A: public class B;

A obj;
A& ref = obj;
A* ptr = &obj;

// 1
static_cast<B&>(ref);
// 2
static_cast<B*>(ptr);

2 个答案:

答案 0 :(得分:6)

不,他们并不总是有相同的成本。启用优化后,它们总是具有相同或非常接近相同的成本。

如果要向上或向下构建一个

的继承层次结构
  • 涉及多重继承,或
  • 多态类继承自非多态类

然后指针的static_cast可能会产生conditional move指令的费用,而参考的static_cast则不会。

这是因为在这些情况下,基类子对象可能与其完整对象的地址不同,因此static_cast可能涉及应用偏移:向源或地址添加或减去常量type对象来计算目标类型对象的地址。

指针可以为null,空指针的static_cast必须产生空指针,因此如果指针为null,则不会应用偏移量。这意味着编译器必须使用条件移动指令来选择是否应用偏移量,具体取决于指针是否为空。

引用不能为null,因此引用的static_cast不需要条件移动。此this指针也是免疫的,因为this指针永远不能为空。

请注意,这也会影响隐式的派生到基础转化,而不仅仅是显式static_cast

通常可以忽略条件移动的成本。如果代码使用指针更具可读性或表达性,则使用指针。为了避免有条件的移动而伤害你的代码几乎总是非常愚蠢。

示例:

struct A { int a; };
struct B { int b; };
struct C : A, B { int c; };

B* cast(C* ptr) { return ptr; }
B& cast(C& ref) { return ref; }

编译器输出:(最新的GCC与-O2

cast(C*):
        leaq    4(%rdi), %rax
        testq   %rdi, %rdi
        movl    $0, %edx
        cmove   %rdx, %rax
        ret
cast(C&):
        leaq    4(%rdi), %rax
        ret

另请注意,如果大多数编译器能够证明指针永远不能为空,那么它们就足够聪明,可以省略条件移动。例如,如果我们在int x = ptr->c;之前插入return ptr;,那么编译器将看到指针间接并且将假定它永远不会为null,因为如果它为null则程序具有未定义的行为,所以它不会&# 39;无论是否将偏移应用于空指针。在这种情况下生成的代码与引用的强制转换相同。

答案 1 :(得分:1)

确实如此 - 您可以放心地假设两种情况下的成本都是空的。结果汇编中唯一的static_cast跟踪(使用MSVC ++测试)是一个额外的指针副本,即使在启用任何优化的情况下也会进行优化。