0

I want to swap two variables with a function. I create two functions my_swap_f1 and my_swap_f2; my_swap_f2 works perfectly but my_swap_f1 throws 2 errors (commented out below).

#include<iostream>
using namespace std;
int my_swap_f1(int &a,int &b){

    int *temp;
    temp=&a;
    //&a=&b;   //throw error
    //&b=temp;    //throw error
}

int my_swap_f2(int *a,int *b){
    //works perfectly
    int temp;
    temp=*a;
    *a=*b;
    *b=temp;
}

int main(){
    int a=10;
    int b=20;
    int temp=0;
    cout<<"Before Swap"<<endl;
    cout<<a<<endl;
    cout<<b<<endl;

    my_swap_f1(a,b); //send value as perameter
    //my_swap_f2(&a,&b); //send address as perameter
    cout<<"After Swap"<<endl;
    cout<<a<<endl;
    cout<<b<<endl;
}

Question: Why are errors thrown in my_swap_f1 and what should I do if I want to swap with my_swap_f1?

Edward
  • 5,942
  • 4
  • 38
  • 55

2 Answers2

5

One of the main reasons to implement swap with references instead of pointers is to avoid all that * and & in the code:

int my_swap_f1(int &a,int &b){
    int temp;
    temp = a;
    a = b;             // a/b refer to the parameters that were passed
    b = temp;          // modifying a reference is the same as modifiying the original
}

That line:

&a = &b;

cannot work, because &a (the address of a) is a rvalue. A rvalue is, sloppy speaking, something that you cannot assign to, it can only appear on the right side of an assignment. If it worked it would mean something like: "Take the address of a and set it to the address of b", but of course you cannot change the address of an object like that.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • "assing" -> "assign" – Millie Smith Oct 24 '17 at 21:34
  • @MillieSmith thx fixed. btw typos like that you can also fix by yourself. Or cant you edit answers? – 463035818_is_not_an_ai Oct 25 '17 at 06:49
  • I just feel like I'm stepping on people's toes when I make a one-character edit for spelling. I guess I would have done it for someone with less rep. – Millie Smith Oct 25 '17 at 15:09
  • @MillieSmith would be completely fine with me. And imho rep is overrated, I could have made all my rep on java and still my c++ answers would look like I know what I am talking about (i didnt and still sometimes I dont know what I am talking about ;). Btw you will get a notification if someone edits your posts so you always have to chance to roll it back – 463035818_is_not_an_ai Oct 25 '17 at 15:41
  • True. I'll edit them from now on and see if I get pushback. Thanks. – Millie Smith Oct 25 '17 at 17:27
1

The difference between my_swap_f1 and my_swap_f2 is that my_swap_f2 declares its arguments to be pointer types, while my_swap_f1 declares its arguments to be reference types. References work differently from pointers in C++, and you are attempting to use references incorrectly in my_swap_f1.

In C++ a reference type is an immutable pointer-like handle, which points to only one instance of the referred-to type and can never be reassigned. It is treated like a value of the referenced type in most expressions, meaning that you can access the referred-to instance "directly" without dereferencing anything. Thus, if you declare a reference variable int &a, the reference a points to exactly one int, and you can access that int's value by just writing a, such as in the assignment int temp = a (note that temp is just an int, not a reference). There's no need to write &a, and doing so will in fact take the address of the int that a refers to (giving you a pointer-to-int), because the "address of" operator (&) will be applied directly to the int value.

This will make more sense if you write your parameter declarations with the "pointer modifier" next to the type name rather than the variable name:

//This function's parameters are two pointers
int my_swap_f2(int* a, int* b);

//This function's parameters are two references
int my_swap_f1(int& a, int& b);

Then, when implementing my_swap_f1, you can change the int value that a refers to by assigning to a directly, because a is a "reference to int." The correct version of your function would be:

void my_swap_f1(int& a, int& b) {
    int temp = a;
    a = b;
    b = temp;
}

Note that in line 3, the assignment overwrites the int that a refers to with the value of the int that b refers to. The references themselves cannot be changed, so there is no need to add any extra symbols (like &) to indicate the referred-to value rather than the reference itself. (Also, I changed the function return type to void, since your code does not actually return a value from the function, and it doesn't need to).

Edward
  • 5,942
  • 4
  • 38
  • 55
  • `&a` takes the address of the variable designated by `a`. There is no such thing as "address of a reference". Many people (including me) dislike the "references are immutable pointers" pedagogy, we feel it causes more confusion than it solves. You certainly could talk about the address of an immutable pointer, but there is no address of a reference. – M.M Oct 24 '17 at 21:08
  • @M.M, yes, you're right, I should have double-checked what `&a` did before posting. I have never tried to take the address of a reference before (why would you?) so I didn't know about this edge case. I fixed my answer to be more accurate. – Edward Oct 24 '17 at 21:24
  • I would change "points to" to "refers to" in the last section. I mean do as you like, but as you started editing it already I thought I mention it... – 463035818_is_not_an_ai Oct 24 '17 at 21:27
  • @tobi303 I explained it that way because the OP seemed to understand pointers but not references, so I thought comparing them to pointers would make sense. But you're right, it's unsafe to assume that references are pointers because that's an implementation detail, so I changed my wording. – Edward Oct 24 '17 at 21:28
  • Should "overwrites the int that a refers to" be "changes the value of the int that a refers to" instead? – Stefano Buora Oct 25 '17 at 13:06