Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cost of a reference to reference static_cast and a pointer to pointer static_cast

Does reference to reference static_cast has the same run time cost as pointer to pointer 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);
like image 923
heavytail Avatar asked Jun 27 '17 13:06

heavytail


People also ask

What is difference between static_cast and Dynamic_cast?

static_cast − This is used for the normal/ordinary type conversion. This is also the cast responsible for implicit type coersion and can also be called explicitly. You should use it in cases like converting float to int, char to int, etc. dynamic_cast −This cast is used for handling polymorphism.

What does static_cast mean in C++?

The static_cast operator converts variable j to type float . This allows the compiler to generate a division with an answer of type float . All static_cast operators resolve at compile time and do not remove any const or volatile modifiers.

How is static_cast implemented?

static_cast is always resolved using compile-time type info. (This may involve a runtime action). If it's not an appropriate cast you either get a compile error or undefined behaviour. In your snippet it is OK because b is a D ; however if b were new B() then the cast compiles but causes undefined behaviour if run.

What happens when static_cast fails?

If static_cast fails you will get a compile error and the program executable will never even be built. Your example has undefined behavior, not a failure or an error.


1 Answers

No, they do not always have the same cost. With optimizations turned on, they always have the same or very nearly the same cost.

If you are casting up or down an inheritance hierarchy in which either

  • multiple inheritance is involved, or
  • a polymorphic class inherits from a non-polymorphic class,

Then a static_cast of a pointer may incur the cost of a conditional move instruction whereas a static_cast of a reference will not.

This is because a base class subobject might not have the same address as its complete object in these cases, so the static_cast may involve applying an offset: adding or subtracting a constant to or from the address of the source type object to compute the address of the destination type object.

Pointers can be null, and a static_cast of a null pointer must produce a null pointer, so if the pointer is null then the offset will not be applied. This means that the compiler must use a conditional move instruction to choose whether or not to apply the offset depending on whether or not the pointer is null.

References can not be null, so no conditional move is needed for a static_cast of a reference. Also the this pointer is immune, as the this pointer can never be null.

Note that this also affects implicit derived-to-base conversions, not just explicit static_cast.

The cost of a conditional move can usually be ignored. If the code is more readable or expressive using pointers then use pointers. Harming your code for the sake of avoiding a conditional move would almost always be very foolish.


Example:

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; }

Compiler output: (latest GCC with -O2)

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

Note also that most compilers are smart enough to omit the conditional move if they can prove that the pointer can never be null. For example, if we insert int x = ptr->c; before return ptr; then the compiler will see the pointer indirection and will assume it can never null, because if it were null then the program has undefined behaviour anyway, so it wouldn't matter if an offset were applied to a null pointer. The code generated in that case would be the same as for a cast of a reference.

like image 176
Oktalist Avatar answered Oct 22 '22 12:10

Oktalist