对引用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);
答案 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 ++测试)是一个额外的指针副本,即使在启用任何优化的情况下也会进行优化。