understanding references in c++ - c++

I have the following code:
int main() {
int x = 3;
int &ref = x;
int &ref2 = ref;
ref = 100;
std::cout <<ref;
std::cout <<ref2;
return 0;
}
This print out 100 and 100. I find it confusing. My understanding was that both ref and ref2 are references to the underlying object (x=3). We then change the value of ref.
As such, I expected 100 and 3.

You don't ever change the value of ref (the language does not let you rebind a reference). In fact, this is why you need to use reference initialisation when you create a reference: you can't write int &ref; ref = x; for example.
The statement ref = 100; changes the value of the object to which the reference is bound.
Hence the output of x, ref, and ref2 are identical.

My understanding was that both ref and ref2 are references to the underlying object (x=3)
Yes.
Well, they're both references to x, whose initial value is 3.
Essentially you have a single integer object, which you can refer to by the names any of the names x, ref or ref2.
We then change the value of ref
No, you're contradicting yourself.
Objects have values. References like ref are not objects, but references to objects, and they don't have a value of their own to change.
You said that ref is a reference, which is true - it is a reference to an object of type int, which can take a value, and whose value is changed when you write ref = 100. The names x, ref and ref2 still refer to the same integer object afterwards, but now its value is 100 instead of 3.
You cannot reseat a reference (make it refer to a different object), and a reference does not have a value to change. It refers to an object, whose value may be changed via the reference.
NB. I don't think this question is quite a duplicate of Can we reassign the reference, even though it contains some of the same misunderstanding.

Related

Why can const int& bind to an int?

In the C++ primer, I found that const int & can bind with a int object.I don't understand that,because I think const int & should bind with a const int not a int object, the int object can change, the book explain this question for that when the const int & object bind with int; there is a temporary object between the two, for example:
int a=0;
const int &r=a;
We can use b as the temporary value, so above is equal that:
const int b=a;
const int &r=b;
But I think the book is not right, because if there is a temporary like b existing between a and r,the value of r can't be changed, but when I debug the following coding in visual studio, I found it is not right:
int a=0;
const int &r=a;
a=3;
cout<<r<<endl;
The output is that r=3; the value of r can be changed, why? I don't understand that.
don't understand that,because I think const int & should bind with a const int not a int object
You are mistaken. A reference-to-const (const reference in short) doesn't mean that only const objects can be bound. It means that the object can not be modified through the reference.
What is not allowed would be to bind a non-const reference to a const object, because such reference could be used to modify the object which would break the constness.
the value of r can be changed, why?
The object that r refers to was modified - which is OK because the object isn't const. r still refers to the same object and the object was not modified using r.
Having a const reference does not mean that the referred object can not change. It means that the object can not be changed using that reference.
If you wish to have an object that can not change, then that object itself has to be const. A const reference does not make the referred object const. The book has shown you how to create a const object:
const int b=a;
I have regarded reference as poiter mistakely,because they are similiar some time.
Indeed, references are very similar to pointers. Regarding the context of this question, they behave similarly. A demo:
int a=0;
const int *r=&a;
a=3;
cout<<*r<<endl;
const in this example only guarantee that a can not be changed where r is used. Usually this is used for functions that do not change input parameters like:
int doNotModifyFoo(const int &foo);
An object cannot be modified "through" a const reference or a pointer to const of it. But a const reference or pointer to const doesn't impose any kind of run-time lock on the underlying object and (assuming it was not declared const) the original declaration or any non-const reference or pointer to non-const can still be used to modify it.
Indeed if the object was not originally declared const then const-ness can be cast away and used to modify the underlying object.
Indeed even if the object was originally declared const this may be possible (but is implementation dependent).
const is a way of indicating that a function (or functions) shouldn't modify an object (either as an argument in our return value out or declaration).
It doesn't (in general) mean the object can't be modified through that or some other reference/pointer.
It also not possible to modify what a reference refers to. Or at least there is no valid way of doing it. In some circumstances it is possible in practice by jiggery pokery of obtaining an address of where a reference is held and modifying it like a pointer. That will usually fail in some circumstances because references are often optimized out of existence and because the compiler knows they 'cannot be modified' such violations might only be partially successful.
In C++, you can refer to non-const objects with references and/or pointers to const.
int x = 10;
const int& r = x; //OK
const int* p = &x; //OK
Of course, since x is not constant it can be changed. However, what you're basically saying by having a const reference to a non-const object is: I will not change this object via this reference/pointer. You still can change the object directly or through other references or pointers.
Think of it as a read-only handle. Yes, the object itself may be mutable, but in many cases you may be willing to acquire and/or provide only a read-only access to that otherwise mutable variable.
int a=0;
const int &r=a;
a=3;
cout<<r<<endl;
The output is that r=3; the value of r can be changed, why? I don't
understand that.
The const only applies to the reference r. It means that you can't change whatever r binded to via r. You can't do:
r = 3;
That will be an error, because r is a const int& and cannot be modified. For now you can think of references as some sort of lightweight transparent "proxy" of an object. So if the "proxy" is const, you cannot modify the object through the "proxy". However, it doesn't mean the original object cannot be modified.
Basically, const int & r promises not to mutate the value it's referencing. This is a stronger guarantee than int &. So, it's possible to refer to an int using a const int & reference. But you may not modify it. It's a subset of the operations possible on the value. However, it's not true the other way around, if you were trying to get a int & reference to an const int value, it would result in a compiler error because the value itself is immutable, and you are trying to get a mutable reference to this immutable value. The operations possible on the int & reference are a superset of what's possible on const int value.
The value of the variable a which is 0 initially is holded at memory.
If you write later: a=5, it'll set that value in memory to 5.
When you write a reference const int & r = a; you are only saying that r should access that same place in memory where 5 is being hold.
Because a is not const it can modify the value.
This is basically how it works.
There are two things:
Const and reference.
Reference is just another name for same memory unit. You can use any name to change the value held at that memory.
A const reference is denoted in C++ by a code like
int j =2;
int const &i = j; //or Alternatively
const int &i = j;
There is no restriction which makes the referred object to be constant as well.
Here, you can not use i to change value of j. However this does not make the memory location j to be constant.You can peacefully change the value of j.
j =3
//but i = 3 will raise an error saying
//assignment of read-only reference ‘i’

Initializing References and Variables In C++

Given the following c++ function:
int& ReturnAReference() {
/* Do something here */
}
Is there any difference between the two statements:
int normalVariable = ReturnAReference();
int& referenceVariable = ReturnAReferene();
Is one version preferred over the other?
Regarding this:
int normalVariable = ReturnAReference();
normalVariable is an integer, and is assigned the value of the int that ReturnAReference() references. As such incrementing, assigning, or doing anything else to normalVariable will not affect whatever ReturnAReference() has internally.
Regarding this:
int& referenceVariable = ReturnAReference();
referenceVariable is a reference to an integer that would otherwise be internal to ReturnAReference(). As such incrementing, assigning, or doing anything else to referenceVariable will affect whatever ReturnAReference() has internally.
What is preferred depends on what you're trying to accomplish, but in many cases the second approach (using referenceVariable) violates "encapsulation" ( http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming) ), which is considered poor design.
EDIT: And I should add that if ReturnAReference() is returning a reference to a variable that is local in that function, that reference will be invalid as soon as ReturnAReference() returns.
After a reference has been initialized, e.g. via
int i = 42;
int& r1 = i;
int& r2 = ReturnAReference();
int& r3(i);
int& r4{i}; // C++11
int& r5 = {i}; // C++11
it becomes an alias, i.e. another name, of the object it has been initialized with. It is not another integer. Note that in the language of the C++ Standard, an object is simply a region of storage, not necessarily an instance of a class.
As a reference is an alias, if you operate with the reference, you'll operate on the original object (the one it has been initialized with):
int i = 42;
int& r = i;
// r is now an alias for i, both refer to the same object
r = 21; // a true assignment
std::cout << i; // will print 21
The statement
int normalVariable = ReturnAReference();
introduces a new object of type int and a name for that object: normalVariable. This object is initialized with the object returned by ReturnAReference(), which means that the value of the returned object is copied into the new object called normalVariable.
On the other hand, the statement
int& referenceVariable = ReturnAReferene();
only introduces a new name for the object returned by ReturnAReference().
If your function would return a non-reference int, like int ReturnAnInt();, the statement
int& r = ReturnAnInt();
would become illegal, as the object returned by this function is a temporary, which only lives until the end of this line (in this case). In the next line, the name r would refer to an object that does not exist any more, so it has been made illegal to bind non-const references to temporary objects.
Let's suppose you have the following definitions :
int test = 4;
int& ReturnAReference() {
return test;
}
1) Is there any difference between the two statements:
int normalVariable = ReturnAReference();
In this case, normalVariable will hold a copy of the return value (not a reference), because the assignment operator copies the value referred by the return value into normalVariable. This means that after
normalVariable = 1;
normalVariable will now be 1, but test will still be 4.
However, if you were to have written
int& referenceVariable = ReturnAReferene();
and do
normalVariable = 1;
normalVariable would now be 1 and test would also be 1, since normalVariable is only an alias for test.
Be careful though when you return a reference. For instance, if you were to do
int& ReturnAReference() {
int i = 0;
return i;
}
the reference returned from ReturnAReference() would not be valid anymore, since it is only valid inside the function and will be destroyed when it is exited.
2) Is one version preferred over the other?
In the case of ints or other primitive types, I would prefer the int return value over int&, simply because an int is small and won't be expensive to copy (it will nearly always fit in a register). Also, the int& return value entails safety issues if the reference refers to a local variable. For classes or structs, it always depends, but you have to be careful when returning local variables by reference or by pointer.
If you want to modify the variable returned by reference from the function, or to keep track of any changes to its value, use int&. It's up to you to make sure the variable you are referencing will exist for as long as you access it. If you just care about the value of the variable returned by reference at that point, use int.
FYI, std::vector's operator [] and at functions return by reference allowing syntax such as the following v.at(0) = 2.

An alias for an alias?

Is it ok to create references for reference variables (alias for an alias in itself ) ?
If yes, what is its application ?
In C++98, it was illegal to form references to reference types. In C++11, there are new reference collapsing rules, which means in a nutshell that a reference to a reference is still just a reference (but there are subtleties regarding lvalue and rvalue references). Consider this code:
typedef int & ir;
int a;
ir & b = a;
In C++98, the last line is illegal, since ir & is not a valid type (an attempted reference to a reference). In C++11, the references collapse and ir & is the same as int &.
Bear in mind that references are immutable, and once initialized you can never change the target of the reference. In the above code, b will always be an alias of a, and can never be changed into an alias to something else. Thus there is no need for a double indirection, as it wouldn't allow you to do anything more than what you already can do with ordinary references.
For completeness, the reference collapsing rules are as follows. Suppose T is not a reference type. Then conceptually we have:
(T&)& == T& (T&)&& == T& (T&&)& == T& (T&&)&& == T&&
You can't create a reference to a reference, and C++ has no reference-to-reference types.
If you use a reference to initialize another reference, for example:
int i = 1;
int &a = i;
int &b = a;
Then what you've actually done is bound the referand of a to b. a is a name for the same object that i is a name for, and consequently int &b = a; has exactly the same effect as int &b = i;. So you have two references to the same object, i.
I can't immediately think of a reason to have two references in the same function, but you'd commonly create multiple references if you have a function f that takes a reference parameter, and passes this on to another function g that also takes a reference parameter. Then f and g each has a reference to the same object.
In Python, like this:
a = 1
b = a
after this processing, the id for "a" and "b" is the same one.

What is a constant reference? (not a reference to a constant)

Why do constant references not behave the same way as constant pointers, so that I can actually change the object they are pointing to? They really seem like another plain variable declaration. Why would I ever use them?
This is a short example that I run which compiles and runs with no errors:
int main (){
int i=0;
int y=1;
int&const icr=i;
icr=y; // Can change the object it is pointing to so it's not like a const pointer...
icr=99; // Can assign another value but the value is not assigned to y...
int x=9;
icr=x;
cout<<"icr: "<<icr<<", y:"<<y<<endl;
}
The clearest answer.
Does “X& const x” make any sense?
No, it is nonsense
To find out what the above declaration means, read it right-to-left:
“x is a const reference to a X”. But that is redundant — references
are always const, in the sense that you can never reseat a reference
to make it refer to a different object. Never. With or without the
const.
In other words, “X& const x” is functionally equivalent to “X& x”.
Since you’re gaining nothing by adding the const after the &, you
shouldn’t add it: it will confuse people — the const will make some
people think that the X is const, as if you had said “const X& x”.
The statement icr=y; does not make the reference refer to y; it assigns the value of y to the variable that icr refers to, i.
References are inherently const, that is you can't change what they refer to. There are 'const references' which are really 'references to const', that is you can't change the value of the object they refer to. They are declared const int& or int const& rather than int& const though.
What is a constant reference (not a reference to a constant)
A Constant Reference is actually a Reference to a Constant.
A constant reference/ Reference to a constant is denoted by:
int const &i = j; //or Alternatively
const int &i = j;
i = 1; //Compilation Error
It basically means, you cannot modify the value of type object to which the Reference Refers.
For Example:
Trying to modify value(assign 1) of variable j through const reference, i will results in error:
assignment of read-only reference ‘i’
icr=y; // Can change the object it is pointing to so it's not like a const pointer...
icr=99;
Doesn't change the reference, it assigns the value of the type to which the reference refers.
References cannot be made to refer any other variable than the one they are bound to at Initialization.
First statement assigns the value y to i
Second statement assigns the value 99 to i
This code is ill-formed:
int&const icr=i;
Reference: C++17 [dcl.ref]/1:
Cv-qualified references are ill-formed except when the cv-qualifiers are introduced
through the use of a typedef-name or decltype-specifier, in which case the cv-qualifiers are ignored.
This rule has been present in all standardized versions of C++. Because the code is ill-formed:
you should not use it, and
there is no associated behaviour.
The compiler should reject the program; and if it doesn't, the executable's behaviour is completely undefined.
NB: Not sure how none of the other answers mentioned this yet... nobody's got access to a compiler?
By "constant reference" I am guessing you really mean "reference to constant data". Pointers on the other hand, can be a constant pointer (the pointer itself is constant, not the data it points to), a pointer to constant data, or both.
As it mentioned in another answers, a reference is inherently const.
int &ref = obj;
Once you initialized a reference with an object, you can't unbound this reference with its object it refers to. A reference works just like an alias.
When you declare a const reference, it is nothing but a reference which refers to a const object.
const int &ref = obj;
The declarative sentences above like const and int is determining the available features of the object which will be referenced by the reference. To be more clear, I want to show you the pointer equivalent of a const reference;
const int *const ptr = &obj;
So the above line of code is equivalent to a const reference in its working way. Additionally, there is a one last point which I want to mention;
A reference must be initialized only with an object
So when you do this, you are going to get an error;
int &r = 0; // Error: a nonconst reference cannot be initialized to a literal
This rule has one exception. If the reference is declared as const, then you can initialize it with literals as well;
const int &r = 0; // a valid approach
First I think int&const icr=i; is just int& icr = i, Modifier 'const' makes no sense(It just means you cannot make the reference refer to other variable).
const int x = 10;
// int& const y = x; // Compiler error here
Second, constant reference just means you cannot change the value of variable through reference.
const int x = 10;
const int& y = x;
//y = 20; // Compiler error here
Third, Constant references can bind right-value. Compiler will create a temp variable to bind the reference.
float x = 10;
const int& y = x;
const int& z = y + 10;
cout << (long long)&x << endl; //print 348791766212
cout << (long long)&y << endl; //print 348791766276
cout << (long long)&z << endl; //print 348791766340

Does reference changes the state of the referent

As I read
---references are not pointers it is the object itself,A reference is an entity that is an alias for another object.
---references can never represent NULL
---Reference variables allow two variable names to address the same memory location:
---it cannot later be made to refer to a different object
---A reference is not a variable as a variable is only introduced by the declaration of an object. An object is a region of storage and, in C++, references do not (necessarily) take up any storage.
now does the below line converts the variable integers to a constant integers
const Array& ref = integers
furthermore I read this
also which says that you can change the state of a referent.
Please suggest/clarify.
No, it does not convert integers. You now just have an alias for integers through which you can't change it. You can still change integers through the original name:
int i = 0;
int const& i_ref = i;
i = 5;
cout << i_ref; // outputs 5
The above examble also shows how you can change the state of the referee.
You cannot change the state of a const reference. Apart from that everything you mentioned in there is true.
So for example:
const int& ref = integers;
ref = 5;
will fail to compile. Where as
int& ref = integers;
ref = 5;
will compile and it will change the value stored in integers to 5.
Furthermore a const reference means that you cannot change value of the object it refers using the reference. You can still modify it using the original variable name. For example:
const int& ref = integers;
integers = 5;
std::cout<<ref<<", "<<integers<<std::endl;
is completely valid and will produce:
5, 5