Reputation: 3954
I wanted to write a function, that takes two pointer and sets the one pointer to where the other is pointing.
My first attempt was this:
void func(int* i1, int* i2)
{
i2 = i1;
}
Then I realised, I am passing the pointers addresses here and were setting the address of the one pointer to the address of the other. Calling this function like this resulted in a segfault:
int * int_ptr_1;
int * int_ptr_2 = nullptr;
int a = 5;
int_ptr_1 = &a;
func(int_ptr_1, int_ptr_2);
std::cout << *int_ptr_2 << std::endl;
But why actually? If the address of int_ptr_2
is now the same as the address of int_ptr_1
, why does dereferencing int_ptr_2
not yield 5
then... int_ptr_1
point to a
, which has a value of 5
...
What is different here from doing this?:
int * int_ptr_1;
int * int_ptr_2;
int a = 5;
int_ptr_1 = &a;
int_ptr_2 = int_ptr_1;
which works just fine...
By research I found out that you can do this instead:
void func(int*& i1, int*& i2)
{
i2 = i1;
}
which will do what I wanted... but... what is the semantics of that anyway?
Upvotes: 2
Views: 100
Reputation: 396
You just passed the pointer contents by value to your function func
. That means that all you do in func
will not affect the outside world, but just modify the (temporary) values that were passed to func
. Instead
void func (int** p1, int** p2)
{
*p2 = *p1;
}
would do the trick. And you would call it like
func (&int_ptr_1, &int_ptr_2);
from your main function. Alternatively, you can pass a pointer reference, as you already described. In that case, the same thing happens behind the scene: The compiler passes an address to a pointer and remembers that each time you use that variable, it has to dereference that address. So it is kind of a syntactic trick to pass a pointer-to-pointer. Both ways have their specific advantages:
The int**
method makes it clear at the point of call that func
is allowed to modify your pointers. (That's why I would prefer it in this case).
The int*&
method is easier to use. I would use it for things like iterators.
[ADDED] As an additional help to the user of your function, I would make the first argument by value, which shows that it is used read only:
void func (int* p1, int** pp2)
{
*pp2 = p1;
}
And you would call that like:
func (int_ptr_1, &int_ptr_2);
See! It is now clear on first sight that int_ptr_1
is just passed by value and not changed inside func
and that int_ptr_2
is the output parameter. If you use this paradigm in your entire code, you will see how much cleared and easier to review it will become.
Hope that helped you clarify things.
Upvotes: 2
Reputation: 65770
void func(int* i1, int* i2)
{
i2 = i1;
}
Here you are passing in two pointers by value and assigning the first to the second. The variables i1
and i2
are scoped to func
and modifying those pointers will not affect anything outside of func
.
void func(int*& i1, int*& i2)
{
i2 = i1;
}
Here the pointers are passed by reference, so modifications to them will affect the variables passed in.
It might seem counter-intuitive at first to think of passing pointers by value and reference, but it's entirely equivalent to passing, say, an int
.
void func(int i1, int i2)
{
i2 = i1; //change only affects func
}
void func(int& i1, int& i2)
{
i2 = i1; //change affects variables passed in
}
Note that you don't need to take i1
by reference, as you won't be modifying it. It's generally best to pass built-in types by value. You could also mark it const
to stop you from making silly mistakes:
void func(int* const i1, int*& i2)
{
i2 = i1;
}
Upvotes: 8