Search code examples
c++c++11pass-by-referencepass-by-valuepass-by-pointer

Pass By Value/Pointer/Reference Clarification


I need a once-and-for-all clarification on passing by value/pointer/reference.

If I have a variable such as

int SomeInt = 10;

And I want to pass it to a function like

void DoSomething(int Integer)
{
    Integer = 1;
}

In my current scenario when passing SomeInt to DoSomething() I want SomeInt's value to be updated based on whatever we do to it inside of DoSomething() as well as be most efficient on memory and performance so I'm not copying the variable around?. That being said which of the following prototypes would accomplish this task?

void DoSomething(int* Integer);
void DoSomething(int& Integer);

How would I actually pass the variable into the function? What is the difference between the previous two prototypes?

Finally if using a function within a class

class SomeClass
{
    int MyInteger;

public:
    void ChangeValue(int& NewValue)
    {
        MyInteger = NewValue;
    }
};

If I pass an integer into ChangeValue, when the integer I passed in get's deleted will that mean when I try to use MyInteger from within the class it will no longer be useable?

Thank you all for your time, I know this is kind of a basic question but the explanations I keep running into confuse me further.


Solution

  • Functionally, all three of these work:

    • pass an int and change the return type to int so you can return the new value, usage: x = f(x);

      • when you plan to set the value without needing to read the initial value, it's much better to use a function like int DoSomething(); so the caller can just say int x = f(); without having to create x on an earlier line and wondering/worrying whether it needs to be initialised to anything before the call.
    • pass an int& and set it inside the function, usage: int x; x = ? /* if an input */; f(x);

    • pass an int* and set the pointed-to int inside the function, usage: int x; x = ?; f(&x);

    most efficient on memory and performance so I'm not copying the variable around

    Given the C++ Standard doesn't dictate how references should be implemented by the compiler, it's a bit dubious trying to reason about their characteristics - if you care compile your code to assembly or machine code and see how it works out on your particular compiler (for specific compiler commandline options etc.). If you need a rule of thumb, assume that references have identical performance characteristics to pointers unless profiling or generated-code inspection suggests otherwise.

    For an int you can expect the first version above to be no slower than the pointer version, and possibly be faster, because the int parameter can be passed and returned in a register without ever needing a memory address.

    If/when/where the by-pointer version is inlined there's more chance that the potentially slow "needing a memory address so we can pass a pointer" / "having to dereference a pointer to access/update the value" aspect of the pass-by-pointer version can be optimised out (if you've asked the compiler to try), leaving both versions with identical performance....

    Still, if you need to ask a question like this I can't imagine you're writing code where these are the important optimisation choices, so a better aim is to do what gives you the cleanest, most intuitive and robust usage for the client code... now - whether that's x = f(x); (where you might forget the leading x =), or f(x) where you might not realise x could be modified, or f(&x) (where some caller might think they can pass nullptr is a reasonable question in its own right, but separate from your performance concerns. FWIW, the C++ FAQ Lite recommends references over pointers for this kind of situation, but I personally reject its reasoning and conclusions - it all boils down to familiarity with either convention, and how often you need to pass const pointer values, or pointer values where nullptr is a valid sentinel, that could be confused with the you-may-modify-me implication hoped for in your scenario... that depends a lot on your coding style, libraries you use, problem domain etc..