According to this question you can't change what a reference refers to. Likewise the C++ Primer 5th Edition states
Once we have defined a reference, there is no way to make that reference
refer to a different object. When we use a reference, we always get the object to
which the reference was initially bound.
However the following code compiles and prints the value 4 which looks to me like the reference was changed?? Please elaborate if this is or is not so.
int a = 2;
int b = 4;
int &ref = a;
ref = b;
cout << ref;
You are not reassigning a reference. A reference acts as an alias for a variable. In this case, ref is an alias for a, so
ref = b;
is the equivalent of
a = b;
You can easily check that by printing out the value of a:
std::cout << a << std::endl; // prints 4
You can understand how references work by comparing their behavior to that of a pointer. A pointer can be thought of as the name of the address of a variable; however a reference is just the name of the variable itself--it is an alias. An alias, once set, can never be changed whereas you can assign a pointer a new address if you want. So you have:
int main(void)
{
int a = 2;
int b = 4;
int* ptr_a = &a;
int& ref_a = a;
ptr_a = &b; //Ok, assign ptr_a a new address
ref_a = &b; //Error--invalid conversion. References are not addresses.
&ref_a = &b; //Error--the result of the `&` operator is not an R-value, i.e. you can't assign to it.
return 0;
}
Related
I am new to C++, and I am studying the concept of reference.
I have studied the fact that a reference should not be assigned to something else once defined and initialized, the description of reference on C++ primer states that once you have bound a reference to an object, then you can't change the object which the reference is bounded to.
I am confused by this statement. I tried the following code on my computer, the compiler didn't report neither warnings nor errors.
int a = 2;
int b = 4;
int &ref = a;
cout << "ref = " << ref << endl;
ref = b;
cout << "ref = " << ref << endl;
On my computer, the compilation passes, and outputs were printed, one is 2, the other is 4, there's no problem at all.
I am confused by this concept of reference, is it the condition that we SHOULD NOT change the object which the reference is bounded to, or we CANNOT change the object which the reference is bounded to?
P.S. Even the page 58 on C++ primer also demonstrates the example where the reference refers to new object, and the book says it's ok to do that. Like this:
int i = 42;
int *p;
int *&r = p;
r = &i; // isn't this changing r to an new object?
*r = 0;
then you can't change the object which the reference is bounded to.
I am confused by this statement
The statement tries to say, that the reference cannot be modified to refer to another object. The object that is referred can be modified.
When left hand operand of assignment is a reference, you are indirecting through the reference, and assigning the value of the referred object.
ref = b;
ref still refers to the object named by a. That object is modified by this assignment. After the assignment, the value of a is 4.
r = &i; // isn't this changing r to an new object?
r still refers to the object named by p. That object is modified by this assignment. After the assignment, p points to i.
I have a simple example here: I used type alias using using keyword for a reference type then I want to know whether I can use that type alias with pointer operator(*) to declare a reference to pointer:
int main(){
using ref_int = int&;
int x = 10;
int* p = &x;
//int*(&rpx) = p;
//ref_int * rptrx = p; // pointer to reference is not allowed.
*ref_int(rptrx) = p; // rptrx is undefined
}
Because as a matter of curiosity when I used the Element-type of std::vector<int>::reference I wanted to combine it with pointer operator * to declare a reference to pointer:
int* ptr = new int(1000);
std::vector<int>::*(reference rptr) = ptr; // error: expected expression
But I can to use pointer type alias combined with reference operator "&" to declare it:
using pInt = int*;
int i = 57;
int* ptrI = &i;
pInt(&rpInt) = ptrI;
cout << *rpInt << endl;
** I know I cannot have a pointer to a reference because a reference is just an alias name for an already existing object while a pointer is an object thus we can have a pointer or a reference to it.
You can't have a pointer to a reference in C++. In C++, references are just aliases for the thing that they refer to, the standard doesn't even require them to take up any storage. Trying to use a reference alias to make a reference to a pointer will not work because using the alias will only ever give you a pointer to a reference type.
So, if you want a pointer to the thing the reference refers to you just use
auto * ptr = &reference_to_thing;
If you want a reference to a pointer that syntax is
int foo = 42;
int* ptr = &foo;
int*& ptr_ref = ptr;
I have read some of the technical differences between references and memory addresses here, however I am trying to find a more abstract way to understand them. Consider the code:
char foo = 'a';
char& bar = foo;
char& bar2 = *(char*)(&foo);
cout << bar << endl;
cout << bar2 << endl;
The output in both cases is 'a'. Is it then correct to conclude from this that a reference (bar2) is simply a memory address (&foo) with an associated type (char)? Or does this explanation fall apart?
The most succinct definition of a reference in C++ is that:
It declares a named variable as a reference, that is, an alias to an already-existing object or function.
Its value is the same as the object it is an alias of.
Its address (obtained by the & operator) is the same as the address of the object it is an alias of.
Any time you have a value (i.e. an object that is the result of evaluating an expression) in C++, you can bind that value to a reference variable. Evaluating the reference later results in an lvalue that is precisely the object which was bound to the reference. For example:
int a = 10;
a; // the value of the expression is immediately discarded
int & r = a; // this time the value is bound to a reference variable
r; // this is the same value as a
r = 20;
Evaluating both a and r produces an lvalue of type int, which is the variable a.
Another example:
Foo f();
f(); // a discarded prvalue of type Foo
Foo && r = f(); // this time the value of f() is bound to r
r.do_stuff();
This time, each evaluation of f() produces a distinct value of type Foo (a "temporary object"). The first one is immediately discarded; the second one is bound to the reference r. Evaluating r produces an lvalue of type Foo, namely the temporary object returned from the second function call.
bar2 is identical to bar, since *(char*)(&foo) (value at the address of foo, interpreted as char) is the same as foo itself.
The important thing to understand here, is that a reference is basically a pointer that is automatically dereferenced, and whose address cannot be changed. Or, in other words, an alias for a variable or memory location.
Consider this:
char *c = new char('x');
char &ref = *c;
ref = 'y';
assert(*c == 'y'); //the memory at c was changed through ref
assert(&ref == c); //the address of ref is the same as c, because ref is an alias for the memory at c
char c2 = 'x';
char &ref2 = c2;
char *p = &c2;
c2 = 'y';
assert(p == &ref2);
assert(ref2 == 'y' && *p == 'y');
I have couple of questions related to usage of references in C++.
In the code shown below, how does it work and not give a error at line q = "world";?
#include <iostream>
using namespace std;
int main()
{
char *p = "Hello";
char* &q = p;
cout <<p <<' '<<q <<"\n";
q = "World"; //Why is there no error on this line
cout <<p <<' '<<q <<"\n";
}
How can a reference q be reinitialized to something else?
Isn't the string literal, p = "Hello", a constant or in read-only space? So if we do,
q = "World";
wouldn't the string at p which is supposed to be constant be changed?
I have read about C++ reference type variables as they cannot be reinitialized or reassigned, since they are stored 'internally' as constant pointers. So a compiler would give a error.
But how actually a reference variable can be reassigned?
int i;
int &j = i;
int k;
j = k; //This should be fine, but how we reassign to something else to make compiler flag an error?
I am trying to get hold of this reference, and in that maybe missed some key things related, so these questions.
So any pointers to clear this up, would be useful.
a) It cannot, the line you quote doesn't change the reference q, it changes p.
b) No the literal is constant, but p is a pointer which points at a literal.
The pointer can be changed, what is being pointed to cannot.
q = "world"; makes the pointer p point to something else.
You seem to think that this code
int i;
int &j = i;
int k;
j = k;
is reassigning a reference, but it isn't.
It's assigning the value of k to i, j still refers to i.
I would guess that this is your major misunderstanding.
An important detail about references that I think you're missing is that once the reference is bound to an object, you can never reassign it. From that point forward, any time you use the reference, it's indistinguishable from using the object it refers to. As an example, in your first piece of code, when you write
q = "World";
Since q is a reference bound to p, this is equivalent to writing
p = "World";
Which just changes where p is pointing, not the contents of the string it's pointing at. (This also explains why it doesn't crash!)
As for your second question, references cannot be reassigned once bound to an object. If you need to have a reference that can change its referent, you should be using a pointer instead.
Hope this helps!
It is to be noted that since C++20, it is possible to change the reference held by a reference variable inside a class, using placement new, like in the following example taken from this SO post:
struct C {
int& i; // <= a reference field
void foo(const C& other) {
if ( this != &other ) {
this->~C();
new (this) C(other); // valid since C++20 even on a class
// with a reference field
}
}
};
int main() {
int a = 3, b = 5;
C c1 {.i = a};
C c2 {.i = b};
c1.foo(c2); // the inner reference field i inside c1
// was referring to a and now refers to b!
}
Code: http://coliru.stacked-crooked.com/a/4674071ea82ba31b
a) How can a reference q be reinitialized to something else?
It cannot be!
An reference variable remains an alias to which it was initialized at time of creation.
b)Isn't the string literal, p = "Hello", a constant/in read only space. So if we do,
No it doesn't.
char* &q = p;
Here q is an reference to pointer of the type char p. The string here is constant put the pointer is not, it can be pointed to another string, and the reference is alias to this pointer not the string literal so it is valid.
c) Second question I have is I have read about C++ reference type variables as they cannot be reinitialized/reassigned, since they are stored 'internally' as constant pointers. So a compiler would give a error.
int i;
int &j = i;
int k;
j = k; //This should be fine, but how we reassign to something else to make compiler flag an error
Does not reassign the reference. it changes the value of the variable to which it was alias.
In this case it changes the value of i to k
Treat reference as an alias name and I hope the world of reference will much easier to understand.
int p; // Declares p as an integer; Defines p & allocates space
int &q = p ; // Declares a Reference. Though they are symbolically 2 variables,
// they essentially refer to same name and same memory location.
So, p = 5 and q = 5 will be all the same.
In your example,
char *p = "Hello"; // Declares your pointer to "Hello". p has its own existence.
char* &q = p; // This now creates a reference (alias) to p with name q.
So all in all, p & q are names of the entity/object (memory).
So, if you assign q something, it reflects in p too. Coz it is same as the assignment to p.
So q = "World", means p too now points to "World". i.e. the Memory location which p & q both refer to - holds the address of first character of "World".
I hope the second question need not be answered if you understand the notion of reference as an alias.
#include<iostream.h>
int main()
{
int a=10;
int &b=a;
cout<<"B"<<'\n'<<b;
cout<<"A"<<'\n'<<a;
b=100;
cout<<"B"<<'\n'<<b;
cout<<"A"<<'\n'<<a;
int c=20;
b=c;
cout<<"C"<<'\n'<<c;
cout<<"B"<<'\n'<<b;
}
A reference is not a const pointer. A const pointer would need to be dereferenced to access the value. You don't need to dereference references.
A reference is an alias - a new name for the same thing. So the code in your question is valid and a and b refer to the same thing.
I hope you are not getting confused with :
b=c;
This will only assign the value of c to b. It will not refer to c. ( It will still refer to a itself)
Your are not assigning a new variable (referee) to b, but a new value to the variable b refers to, in this case a.
A reference is similar to a const pointer but not to a pointer to const object.
const int* p; //can't change the value of *p
int* const p; //can't change p (make it point to a different int)
References are similar to the latter - once initialized, they can't be made to refer to another object.
Reference is not pointer at all.
int const & b1 = a; // const reference
int & b2 = a // non-const reference
when you are doing b = c, you are not referring to c instead you are just assigning value of c to b. If you want verify increment value of c and print both b and c.