How does a swap function work with references? - c++

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?

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.

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).

Related

Why cannot assign value to non-const reference?

Why these definitions are all ok:
int func(int p=255) {
return p;
}
int func1(const int &p=255) {
return p;
}
but this definition:
int func2(int &p=255) {
return p;
}
leads to compile error ?
What is the logic behind it ?
Taking arguments by reference means, you dont work with your local copy of the variable, but with a variable already defined in the scope of the calling function.
While your first example makes sense (you have a local variable p that you can fill with a default value) the second example is a bit more tricky: Usually when using references you expect the variable to have an address, since you want to modify it. For const-refernces, the compiler will still allow you to pass a literal, even if something like "reference to a literal" makes no sense at all.
In the third case the compiler expects you to modify p. But what part of the memory should this modification affect? "255" has no address - therefore it cant be used as a reference.
If you want to have a more detailed explanation, you should probably look for keywords like "rvalue" and "lvalue".
The attempted function definition
auto func2( int& p = 255 )
-> int
{ return p; }
… fails because you can't bind an rvalue to a reference to non-const. Basically that rule is because a simple value like 255 isn't modifiable. While the reference can be used to modify.
One simple solution is to express the default as a separate overload:
auto func2( int& p )
-> int
{ return p; }
auto func2()
-> int
{
int scratchpad = 255;
return func2( scratchpad );
}
A non-const reference must be bound to lvalue (i.e. its address could be got). 255 (i.e. an int literal) is not a lvalue, so int &p=255 fails.
A const reference could be bound to rvalue, and for this case, a temporary int will be created and initialized from 255. The temporary int's lifetime will be the same as the const reference.
int func(int p=255) {
return p;
}
p here is copied by value, and it is defined to exist in the scope of func.
int func2(int &p) {
return p;
}
// e.g. use:
int value = 10;
func2(value); // func2 *could* modify value because it is passed by non-const reference
In this case the compiler here expects p to have a name somewhere in memory (i.e. lvalue), so it can possibly write to it within func2. Passing by non-const reference allows you to modify the variable used in the function call. Since p must belong to someone else somewhere since it can be modified, you can't assign a default value to it.
But what about the const-reference case? Here, the compiler is smart enough to know that p can never be written to since it is const, so it doesn't need to have a name in memory to write to. In cases of a literal being passed (e.g. 255), it (behind the scenes) essentially creates a temporary and passes that temporary variable to the function.
int func1(const int &p=255) {
return p;
}
func1(10);
// Behind the scenes, the compiler creates something along these lines
// since it can never be modified.
const int some_temporary = 10;
func1(some_temporary);

declaration of reference and pointer in c++

For example, if F is a reference to an integer, where the reference is not permitted to be pointed to a new object once it is initially pointed to one.
Can I write to declaration like: const int & F?
I am confused about reference and pointer, because they both represent the address of something, but we always write parameter use reference as: const & F, I understand that this is to reduce the copy and does not allow others to change it, but are there any other meanings? and why do we need "const" after a function declaration like: int F(int z) const; this const makes the return type const or everything in the function const?
One more example,
void F(int* p)
{
p+=3;
}
int z=8;
F(&z);
std::cout<<z<<std::endl;
What is the output for z since z is a reference, and I pass it as a pointer who points to an integer.Increasing p by 3 just makes the address different and does not change its value?
Just a first pass at some answers - if anything is unclear please comment and I'll try to elaborate.
int a = 3;
declares an integer, a, with the initial value 3, but you are allowed to change it. For example, later you can do
a = 5; // (*)
and a will have the value 5. If you want to prevent this, you can instead write
const int a = 3;
which will make the assignment (*) illegal - the compiler will issue an error.
If you create a reference to an integer, you are basically creating an alias:
int& b = a;
, despite appearances, does not create a new integer b. Instead, it declares b as an alias for a. If a had the value 3 before, so will b, if you write b = 6 and print the value of a, you will get 6 as well. Just as for a, you can make the assignment b = 6 illegal by declaring it as const:
const int& b = a;
means that b is still an alias for a, but it will not be used to assign a different value to a. It will only be used to read the value of a. Note that a itself still may or may not be constant - if you declared it as non-const you can still write a = 6 and b will also be 6.
As for the question about the pointers: the snippet
void F(int* p) {
p += 3;
}
int z = 8;
F(&z);
does not do what you expected. You pass the address of z into the function F, so inside F, the pointer p will point to z. However, what you are doing then, is adding 3 to the value of p, i.e. to the address that p points to. So you will change to pointer to point at some (semi)random memory address. Luckily, it's just a copy, and it will be discarded. What you probably wanted to do, is increment the value of the integer that p points to, which would be *p += 3. You could have prevented this mistake by making the argument a int* const, meaning: the value of p (i.e. address pointed to) cannot be changed, but the value it points to (i.e. the value of z, in this case) can. This would have made *p += 3 legal but not the "erroneous" (unintended) p += 3. Other versions would be const int* p which would make p += 3 legal but not *p += 3, and const int* const` which would have allowed neither.
Actually, the way you have written F is dangerous: suppose that you expand the function and later you write (correctly) *p += 3. You think that you are updating the value of z whose address you passed in, while actually you are updating the value of a more-or-less random memory address. In fact, when I tried compiling the following:
// WARNING WARNING WARNING
// DANGEROUS CODE - This will probably produce a segfault - don't run it!
void F(int* p) {
p += 3; // I thought I wrote *p += 3
// ... Lots of other code in between, I forgot I accidentally changed p
*p += 3; // NOOOOOOOOOOO!
}
int main()
{
int z=8;
F(&z);
std::cout << z;
return 0;
}
I got a segmentation fault, because I'm writing at an address where I haven't allocated a variable (for all I know I could have just screwed up my boot sector).
Finally, about const after a function declaration: it makes the this pointer a const pointer - basically the compiler emits const A* this instead of just A* this. Conceptually, it states your intention that the function will not change the state of the class, which usually means it won't change any of the (internal) variables. For example, it would make the following code illegal:
class A {
int a;
void f() const {
a = 3; // f is const, so it cannot change a!
}
};
A a;
a.f();
Of course, if the function returns something, this value can have its own type, for example
void f();
int f();
int& f();
const int f();
const int& f();
are functions that return nothing, a (copy of) an integer, a (reference to) an integer, a constant (copy of) an integer, and a constant reference of an integer. If in addition f is guaranteed not to change any class fields, you can also add const after the brackets:
void f() const;
int f() const;
int& f() const;
const int f() const;
const int& f() const;
The way I remember the difference between references and pointers is that a reference must exist and the reference cannot change.
A pointer can be changed, and usually needs to be checked against NULL or tested to verify it points to a valid object.
Also, an object passed by reference can be treated syntactically like it was declared in the function. Pointers must use deferencing syntax.
Hope that helps.
You are confusing things.
First of all int z=8; F(&z); here z IS NOT a reference.
So let me start with the basics:
when found in a type declaration the symbol & denotes a reference, but in any other context, the symbol & means address of.
Similar, in a type declaration * has the meaning of declaring a pointer, anywhere else it it the dereferencing operator, denoting you use the value at an address.
For instance:
int *p : p is a pointer of type int.
x = *p : x is assigned the value found at address p.
int &r = a : r is reference of type int, and r refers the variable a.
p = &a : p is assigned the address of variable a.
Another question you have: the const at the end of a function, like int f(int x) const. This can be used only on non-static class methods and specifies that the function does not modify the object. It has nothing to do with the return value.

Changing constant pointer's address

I'm trying to understand one thing.
I know I can't change constant pointer's value, but I can change its address, if I initialize a pointer the following way:
int foo = 3;
const int *ptr = &foo;
*ptr = 6; // throws an error
int bar = 0;
ptr = &bar; // foo == 0
Now, let's say I declare (/define, I never remember which one) a function:
void change(const int arr[], int size);
int main() {
int foo[2] = {};
change(foo, 2);
std::cout << foo[0];
}
void change(const int arr[], int size) {
// arr[0] = 5 - throws an error
int bar = 5;
arr = &bar;
}
The last line in the code above doesn't throw any errors. However, when the function is over and I display the first element, it shows 0 - so nothing has changed.
Why is that so?
In both situations I have constant pointers, and I try to change its address. In the first example it works. In the second one it doesn't.
I also have another question. I've been told that if I want to pass two-pointers type to the function, const keyword won't work as expected. Is that true? And if so, then what's the reason?
You're screwing up the terminology a lot, so I'm going to start there because I think it is a major cause of your confusion. Consider:
int x;
int* p = &x;
x is an int and p is a "pointer to int". To modify the value of p means to change p itself to point somewhere else. A pointers value is the address it holds. This pointer p holds an address of an int object. To change the pointer's value doesn't mean to change the int object. For example, p = 0; would be modifying p's value.
In addition to that, the address of p is not the address it holds. The address of p would be what you get if you did &p and would be of type "pointer to pointer to int". That is, the address of p is where you would find the pointer p in memory. Since an object doesn't move around in memory, there's no such thing as "changing its address".
So now that's out of the way, let's understand what a constant pointer is. const int* is not a constant pointer. It's a pointer to a constant object. The object it points to is constant, not the pointer itself. A constant pointer type would look more like int* const. Here the const applies to the pointer, so it is of type "const pointer to int".
Okay, now I'll quickly give you an easy way to remember the difference between declaration and definition. If you bought a dictionary and all it had was a list of words in it, would you really call it a dictionary? No, a dictionary is supposed to filled with definitions of words. It should tell you what those words mean. The dictionary with no definition is only declaring that such words exist in the given language. So a declaration says that something exists, and a definition gives the meaning of it. In your case:
// Declaration
void change(const int arr[], int size);
// Definition
void change(const int arr[], int size) {
// arr[0] = 5 - throws an error
int bar = 5;
arr = &bar;
}
Now to explain the issue here. There's no such thing as an array argument type. Any array type argument is converted to a pointer. So the declaration of change is actually identical to:
void change(const int arr*, int size);
when you do arr = &bar; you are simply assigning the address of bar to the pointer arr. That has no effect on the array elements that arr is pointing to. Why should it? You are simply changing where arr points to, not the objects it points at. And in fact you can't change the objects it points at because they are const ints.
I know I can't change constant pointer's value, but I can change its address
Nah. You can't change the address of anything. Did you mean that you can't change the object it points to, but you can change the pointer itself? Because that's what is the truth - in the case of a pointer-to-const type. However, if you have a const pointer to a non-const object, then you can't change the pointer, you can only change whatever it points to.
Addendum (edit): a handy rule of thumb is that const applies to what stands on its left side, except when nothing stands on its left side, because then it applies to the type that is on its right side. Examples:
const int *ptr;
int const *ptr; // these two are equivalent: non-const pointer to const int
int *const ptr; // const pointer to non-const int
int const *const ptr; // const pointer to const int
const int *const ptr; // same as above
However, when the function is over and I display the first element, it shows 0 - so nothing has changed.
Scope. arr is a function argument - so it's local to the function. Whatever you do with it, it won't be effective outside of the function. To achieve what you want, declare it as a reference:
void change(const int *&arr, int size)
I've been told that if I want to pass two-pointers type to the function, const keyword won't work as expected. Is that true?
This depends on what your expectations are. If you read the standard attentively and have proper expectations, then it will indeed work as expected. Examples:
const int **ptr; // pointer to pointer to const int
int const **ptr; // same as above
const int *const *ptr; // pointer to const pointer to const int
etc. You can generate more of these funky declarations using CDecl
The first thing is using the proper terms, which actually helps in understanding:
const int *ptr = &foo;
That is a pointer to a constant integer, not a constant pointer to an integer. You cannot change the object pointed, but you can change the pointer to refer to a different object.
void change(const int arr[], int size);
That signature is processed by the compiler as void change( const int *arr, int size ), and I'd recommend that you type it as that, as it will reduce confusions. Where the function is called, change(foo,2), the compiler will transform the argument foo (type is int[2]) to &foo[0] which has type const int* (both transformations are commonly called decay of the array to a pointer).
Now as in the first block of code, you cannot change the pointed memory, but you can change the pointer to refer to a different object.
Additionally, in C++ the default mode is pass-by-value. The pointer arr inside change is a copy of the value &foo[0]. Inside the function you are changing that copy, but that will not affect anything outside of the function context.
const int * is doing what it's supposed to do, what's confusing you is its purpose.
Think of it as a pointer to a readonly int. You can point to any int you want, but it's going to be readonly no matter what.
You might use this to loop through an array of type const int, for example.

pointer reference type

I am trying to write a function that takes a pointer argument, modifies what the pointer points to, and then returns the destination of the pointer as a reference.
I am getting the following error: cannot convert int*** to int* in return
Code:
#include <iostream>
using namespace std;
int* increment(int** i) {
i++;
return &i;
}
int main() {
int a=24;
int *p=&a;
int *p2;
p2=increment(&p);
cout<<p2;
}
Thanks for helping!
If you indeed mean "return the destination of the pointer as a reference", then I think the return type you're after is int& rather than int*.
This can be one of the confusing things about C++, since & and * have different meanings depending on where you use them. & is "Reference type" if you're talking about a variable definition or return type; but it means "Address of" if it's in front of a variable being used after it's defined.
I could be completely mistaken, but it seems to me that you've gotten these two meanings mixed up; and since you want to return a reference, you've written "return &i", since & is used for references. However, in this case, it returns the address of i. And since i is a pointer to a pointer to an int, in this line of code:
int* increment(int** i) { i++; return &i;}
you are returning the address of a pointer to a pointer to an int. That is why you are getting your error message cannot convert int***' to int*.
Let's walk through your code line by line. You are after a program that takes a pointer and returns a reference. So that would be:
int& increment(int* i)
We don't need the double pointer that you had in your code (unless you want a pointer to a pointer). Then you want it to modify what the pointer points to:
(*i)++;
And then return the destination of the pointer as a reference:
return *i;
Here, we are dereferencing i. Remember that using references lets you treat them like normal variables, and handles the pointer stuff for you. So C++ will figure out that you want it to be a reference.
Then, to use your code, you can do pretty much what you had, but using less pointers:
int a=24;
int *p=&a;
int *p2;
p2 = increment(p);
I haven't tested any of this, so anyone may feel free to edit my answer and fix it if I've got something wrong.
int* increment(int** i) { (**i)++; return *i;}
and
cout << *p2;

In C++, what does & mean after a function's return type?

In a C++ function like this:
int& getNumber();
what does the & mean? Is it different from:
int getNumber();
It's different.
int g_test = 0;
int& getNumberReference()
{
return g_test;
}
int getNumberValue()
{
return g_test;
}
int main()
{
int& n = getNumberReference();
int m = getNumberValue();
n = 10;
cout << g_test << endl; // prints 10
g_test = 0;
m = 10;
cout << g_test << endl; // prints 0
return 0;
}
the getNumberReference() returns a reference, under the hood it's like a pointer that points to an integer variable. Any change applyed to the reference applies to the returned variable.
The getNumberReference() is also a left-value, therefore it can be used like this:
getNumberReference() = 10;
Yes, the int& version returns a reference to an int. The int version returns an int by value.
See the section on references in the C++ FAQ
Yes, it's different.
The & means you return a reference. Otherwise it will return a copy (well, sometimes the compiler optimizes it, but that's not the problem here).
An example is vector. The operator[] returns an &. This allows us to do:
my_vector[2] = 42;
That wouldn't work with a copy.
The difference is that without the & what you get back is a copy of the returned int, suitable for passing into other routines, comparing to stuff, or copying into your own variable.
With the &, what you get back is essentially the variable containing the returned integer. That means you can actually put it on the left-hand side of an assignment, like so:
getNumber() = 200;
The first version allows you to write getNumber() = 42, which is probably not what you want. Returning references is very useful when overloading operator[] for your own containers types. It enables you to write container[9] = 42.
int& getNumber(): function returns an integer by reference.
int getNumber(): function returns an integer by value.
They differ in some ways and one of the interesting differences being that the 1st type can be used on the left side of assignment which is not possible with the 2nd type.
Example:
int global = 1;
int& getNumber() {
return global; // return global by reference.
}
int main() {
cout<<"before "<<global<<endl;
getNumber() = 2; // assign 2 to the return value which is reference.
cout<<"after "<<global<<endl;
return 0;
}
Ouptput:
before 1
after 2
"&" means reference, in this case "reference to an int".
It means that it is a reference type. What's a reference?
Wikipedia:
In the C++ programming language, a reference is a simple reference datatype that is less powerful but safer than the pointer type inherited from C. The name C++ reference may cause confusion, as in computer science a reference is a general concept datatype, with pointers and C++ references being specific reference datatype implementations. The declaration of the form:
Type & Name
where is a type and is
an identifier whose type is reference
to .
Examples:
int A = 5;
int& rA = A;
extern int& rB;
int& foo ();
void bar (int& rP);
class MyClass { int& m_b; /* ... */ };
int funcX() { return 42 ; }; int (&xFunc)() = funcX;
Here, rA and rB are of type "reference
to int", foo() is a function that
returns a reference to int, bar() is a
function with a reference parameter,
which is reference to int, MyClass is
a class with a member which is
reference to int, funcX() is a
function that returns an int, xFunc()
is an alias for funcX.
Rest of the explanation is here
It's a reference
It means it's returning a reference to an int, not an int itself.
It's a reference, which is exactly like a pointer except you don't have to use a pointer-dereference operator (* or ->) with it, the pointer dereferencing is implied.
Especially note that all the lifetime concerns (such as don't return a stack variable by address) still need to be addressed just as if a pointer was used.