5

Is there a difference or preferred way of altering a pointer in a function? Take this snippet for example

    void change(int** ptr) {
        **ptr = 50;
        *ptr = nullptr;
    }

    void change(int*& ptr) {
        *ptr = 50;
        ptr = nullptr;
    }

    int main()
    {
        int a = 5;

        int* ptr = &a;
        int** ptr2 = &ptr;

        std::cout << "value: " << a << std::endl;
        std::cout << "value: " << ptr << std::endl;
        std::cout << "value: " << ptr2 << std::endl;

        change(ptr2);
        //change(ptr);

        std::cout << "value: " << a << std::endl;
        std::cout << "value: " << ptr << std::endl;
        std::cout << "value: " << ptr2 << std::endl;


        system("pause");

    }

It seems like both of the change functions can achieve what I'm asking, but I'm not sure on the difference, other than the reference function doesn't create a copy of the pointer?

jjmcc
  • 795
  • 2
  • 11
  • 27
  • The pointer-to-pointer function doesn't copy `ptr` either. – StoryTeller - Unslander Monica Aug 29 '18 at 12:34
  • 3
    in C++ it's preferred to not use raw pointers – bolov Aug 29 '18 at 12:39
  • There is no difference in performance, references are pointers in the end –  Aug 29 '18 at 12:42
  • @user2176127 The "As-If" rule would be a better reference for there being no difference in performance. References don't have to be implemented as pointers, and pointers can sometimes be "dereferenced" by the compiler – Caleth Aug 29 '18 at 12:50
  • `ptr*` names a type; `ptr**` is a pointer to that type, and `ptr*&` is a reference to that type. This question is exactly the same as asking about the difference between `int*` and `int&`. – Pete Becker Aug 29 '18 at 14:54

3 Answers3

3

You can have a null pointer, but not a null reference.

You can supply the first with nullptr, and it will compile1, because there is an implicit conversion from std::nullptr_t to int**. If you tried to supply the second with nullptr, it will fail. The best match would be the conversion std::nullptr_t to int*, but you can't bind a mutable reference to a temporary.

I go over various situations for different ways of parameter passing in this answer, which also includes object ownership considerations (with std::unique_ptr)

1. The behaviour will be undefined, because you dereference it.

Caleth
  • 52,200
  • 2
  • 44
  • 75
1

Is there a difference ... between ptr** and ptr*& ...

Yes. The former is a pointer, to an object of type ptr*, while the latter is a reference to an object of type ptr*.

or preferred ...

void change(int** ptr) {
    **ptr = 50;
    *ptr = nullptr;
}

void change(int*& ptr) {
    *ptr = 50;
    ptr = nullptr;
}

Advantages of a reference

You'll find that the reference is implicitly indirected, which makes the syntax simpler and that usually helps readability. This is particularly important in case of reference / pointer to a pointer. Same advantage applies to getting a reference: You don't need to use the address-of operator.

Another advantage is that a reference cannot be reassigned to refer to another object. This makes it simpler to read programs that use references, since you don't need to figure out whether a reference is reassigned within a long algorithm; You know that it isn't.

Another advantage is that a reference cannot be null. Therefore you don't need to check for such eventuality within the function. If you pass null to the first example function, the behaviour would be undefined, which is a very bad thing.

Disadvantages of a reference

You'll find that the reference is implicitly indirected. This can be confusing to people who are familiar with only value types (C programmers).

Another disadvantage is that a reference cannot be reassigned to refer to another object. This appears to not be a problem for your function since you don't need to refer to more than one object, but in general, there are situations where it would be useful.

Another disadvantage is that a reference cannot be null. This appears to not be a problem for your function which is presumably never intended to handle such case. But in general, there are situations where you want to represent a referential relation to non-existing object.


Preferences are personal, but in my opinion, the advantages of the reference outweigh the disadvantages, except when you need one of the features that are not possible (nullability, re-assignment)

eerorika
  • 232,697
  • 12
  • 197
  • 326
0

It's largely a matter of personal taste.

That said, when calling void change(int** ptr), because you'd tend to pass the address of something using &, it is clearer at the calling site that the "something" could be modified by the function. If you use the int*& ptr overload, it's not as clear as the calling syntax is identical for pass-by-value and pass-by-reference.

Aside from the above, I tend to use pointers as function parameters if nullptr is allowed, and references if not.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483