Search code examples
c++referencecompiler-optimizationabi

What is the cost of calling a function which takes a reference with a dereferenced pointer?


Is there any cost to convert from pointer to ref in the following type of code?

void bar(Obj&);

void foo(Obj* o) {
    bar(*o); 
}

On one hand, the value of the pointer is the address of Obj, so the compiler could just re-interpret the value as a reference. However, if o is a null pointer, then that deref would crash so, presumably, there is a memory read there. The compiler doesn't have context on whether the pointer is valid or not.

I understand that in some cases, the compiler could elide reads for conversions, when it has enough context near the conversion.

I found this other question, but that answer is for a different scenario: Cost of converting a pointer to a vector into a reference


Solution

  • In practice, there is no cost to this operation. To visualize this, you could compile the following code with optimizations enabled:

    struct Obj;
    
    void bar(Obj&);
    
    void foo(Obj* o) {
        bar(*o); 
    }
    

    GCC compiles this to:

    foo(Obj*):
            jmp     bar(Obj&)
    

    At the ABI level, pointers and references are both passed as the memory address of the object they are referring to, so they're interchangeable without any operation.

    However, if o is nullptr, then that deref would crash so, presumably, there is a memory read there.

    No, that doesn't necessarily happen. If o is a null pointer, dereferencing it is undefined behavior. That doesn't mean that the program has to crash; it just means that anything can happen in that scenario. In this case, it results in a reference being bound to something that's not an actual object, which is meant to be impossible. This will probably break some code further down the line.

    I understand that, in some cases, the compiler could elide reads for conversions, when it has enough context near the conversion.

    There is neither a read nor a conversion in this code, at least not in the C++ standard sense. Dereferencing the pointer does not read from the pointed-to object, and binding references is not considered a conversion.