I'm currently reading c++ Primer and in one of the exercises, it shows 2 types of reference initializations, one const and and one not, and in the one const, the reference points to 0.. I thought references could only point to objects!!
int i = -1, &r = 0; // illegal, r must refer to an object.
const int i = -1, &r = 0; // legal.
So the first one, int variable i is -1. Then int reference r refers to 0 which is
invalid,gotcha
Now in the second one, const int i = -1, then const reference r = 0.. How?
I know references can't be const, the const is what the reference is referring to, and the book said that const references can refer to both const and non const objects(of the same type). This still doesn't explain why it can point to 0, which is not an object at all..
I'm not sure how the second statement is valid, someone please explain!
In
const int &r = 0;
a temporary object is created with the value 0, and then r is bound to that object. This is allowed because a const reference is allowed to bind to an rvalue. It also works with an rvalue reference:
int&& r = 0; // ok
However, it won't work with int& because an int& variable can only bind to an lvalue.
Note that the temporary object that the reference binds to will live until the reference goes out of scope. See https://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
C++ specifically allows that an rvalue be bound to a const lvalue reference, so this is perfectly standard-conforming:
const int &r = 0;
Reference
An rvalue may be used to initialize a const lvalue reference, in which case the lifetime of the object identified by the rvalue is extended until the scope of the reference ends.
Related
why this binding is ok
int main()
{
double d = 4.56;
const int &r = d;
return 0;
}
but this is not
int main()
{
double d = 4.56;
int &r = d;
return 0;
}
can anyone explain me while the first one compile but second one shows error
When you bind to a converted type (the double has to be converted to an int), you get a prvalue, since the converted int is a temporary with no address in memory. Therefore, binding a regular reference to it doesn't work, because they can only bind to glvalues. const type references can bind to prvalues, so the first one compiles still. Source: https://en.cppreference.com/w/cpp/language/value_category
An int reference cannot be bound to an object of type double, because the types mismatch.
So in order to make the initialization of the reference work at all, a new temporary object of the correct type int must be created. This is possible because there is an implicit conversion sequence from double to int.
The reference should then bind to this temporary, i.e. to a rvalue expression, but only const lvalue references are allowed to bind to rvalues. Non-const lvalue references are not allowed to do that, making the second program ill-formed.
Note that in the first program, although the reference is bound to a temporary object that would usually be destroyed at the end of the full-expression that it was created in, binding to a reference extends the lifetime of that temporary object to the lifetime of the reference. So using r in the first program is actually ok.
However, access through r will not refer to d, but to that new temporary object that is independent of d, which may be surprising, and therefore I think it is not a good idea to write like that. Use auto& or const auto& to make sure that r will certainly refer to d and that there is never any implicit conversion happening due to a type mismatch. If you want the conversion, just use int instead of a reference to int.
What is the purpose for the "const" keyword for a reference if the object it is referencing is not a const object? Is there any difference between what r1 and r2 does (below)?
int i = 42; // non const object
const int &r1 = i; // const reference to non const object
int j = 25; // non const object
int &r2 = j; // non const reference to non const object
Here's a quote from CPP Primer 5th:
"C++ programmers tend to abbreviate the phrase “reference to const” as
“const reference.” This abbreviation makes sense—if you remember that it
is an abbreviation.
Technically speaking, there are no const references. A reference is not an
object, so we cannot make a reference itself const. Indeed, because there
is no way to make a reference refer to a different object, in some sense all
references are const. Whether a reference refers to a const or nonconst
type affects what we can do with that reference, not whether we can alter
the binding of the reference itself."
I think this means that making a reference a "const" when it is referenced to a non const object does absolutely nothing. We may as well take that const keyword out when defining that reference.
Asking this question here for confirmation.
Edit: Looks like my initial conjecture is wrong. I understand now that a const reference to a non const object does have a purpose: to prevent the reference from modifying the object. The non const object can still be modified by other means but not by this const reference.
Thanks all.
"What is the purpose for the "const" keyword for a reference if the object it is referencing is not a const object?"
The purpose is to prevent that reference being used to modify the object it is referencing.
int i = 42; // non const object
const int &r1 = i; // const reference to non const object
r1 = 6 * 9; // error, r1 cannot be used to modify i;
To understand it better you can look into difference between const pointer and pointer to a const data:
int i, j;
const int *p1 = &i; // pointer to constant int
int *const p2 = &i; // constant pointer to int
*p1 = 0; // error, p1 points to const int
*p2 = 0; // it is fine sets i to 0
p1 = &j; // fine p1 now points to anbother int
p2 = &j; // error, p2 is a constant pointer
so now if we replace pointer to reference we can see similar things, except reference by itself is not changeable ie you cannot make reference to refer to another object after it is created (unlike non constant pointer) and any reference is like constant pointer. So const reference in this meaning does not make any sense and usually by const reference people mean reference to a const type. That what quote from primer means.
As for difference in your code, yes there is difference - you cannot change object through const reference does not matter if that reference points to const object or not.
There's a useful way to figure out what constness means in pointers and references, which is to read the declaration from right to left (see these answers). So const int &r1 can be read as "r1 is a reference to an int const".
Basically, r1 refers to an int which cannot be modified. This means that the referred-to int is either a const int, or it's a simple int. The binding of a const const reference to a non-const object (for example, when writing something like int i = 5; const int& r = i;) is perfectly legal because there's nothing wrong with not modifying a non-const object.
I think this means that making a reference a "const" when it is referenced to a non const object does absolutely nothing. We may as well take that const keyword out when defining that reference.
Not true.
You may not modify the a non-const object through a const reference.
You may modify a non-const object through a non-const reference.
Unless an object is created in the read-only section of a program, it is open for modifiction without adverse consequences. However, when you use a const reference to a non-const object, you are asking the compiler to not let you modify the object through that particular reference. It does not mean that you will not modify object.
It's similar to function arguments. When a function uses a const reference argument type, the function is promising to you that it will not modify the object. It does not mean that the object is not modifiable at all.
If we use const with variable then its value can not be change and when it is used with const reference then its reference can not be changed if we used it with object then whole data is used in object it can not be changed.
It's also worth to mention the behavior when you pass both to a function call
fun1(const int& R1) vs. fun2(int & R1)
In fun1 you may call it with either cost or variable, for example fun1(5) or fun1(var1); assuming int var1=5;
In fun2, you simply can't call it with const, fun2(5) will give you compiler error, which means in that case you've to add another overloading implementation to cover this case. Bad design!
I'm new to C++. I'm trying to learn the concept of const. Could someone please tell me why the first statement is illegal while the second is legal?
int i = -1, &r = 0;
const int i = -1, &r = 0;
i is a red herring here, the issues are int &r = 0; vs. const int &r = 0;
A non-const lvalue reference must bind directly to an lvalue. 0 is not an lvalue, so int &r = 0; fails.
A const lvalue reference may be bound to an rvalue. When this happens, it is not bound directly. Instead, a temporary (of type const int here) is created and copy-initialized from the rvalue. The temporary has its lifetime extended by virtue of this binding.
So const int &r = 0; is legal and has a similar effect to const int __temp = 0; const int &r = __temp;
int i = -1, &r = 0; is same as:
int i = -1;
int &r = 0;
The problem here is you can't write int &r = 0;, because initialization of a reference need the initializer to be an lvalue (an object whose address
you can take), while the literal 0 is not.
But the initializer of a const reference need not to be an lvalue, so const int &r = 0; is fine.
The i = -1, bit creates an i variable initialised to -1, but makes no difference to the references that come after, so let's focus on:
int &r = 0; // illegal
const int &r = 0;
What the const int& version does is extend the lifetime of the value it's bound to: in other words, the 0 value is kept around for use via r, until the end of the scope in which r is defined.
It's easy to point out that the same generosity is not extended to the int& version "because it's not an lvalue". The more interesting question of why is discussed in the C++ FAQ:
In C++, non-const references can bind to lvalues and const references can bind to lvalues or rvalues, but there is nothing that can bind to a non-const rvalue. That's to protect people from changing the values of temporaries that are destroyed before their new value can be used. For example:
void incr(int& a) { ++a; }
int i = 0;
incr(i); // i becomes 1
incr(0); // error: 0 is not an lvalue
If that incr(0) were allowed either some temporary that nobody ever saw would be incremented or - far worse - the value of 0 would become 1. The latter sounds silly, but there was actually a bug like that in early Fortran compilers that set aside a memory location to hold the value 0.
int i = -1, &r = 0; is basically equivalent to writing
int i = -1;
int &r = 0
The second statement tries to bind a non-const lvalue to 0, which is not an lvalue at all (0 is not an object whose address can be taken). However, it succeeds when it is a const lvalue as that be bound (not directly though) to an rvalue.
I came across a code snippet
const int& reference_to_const_int = 20;
cout<<"\n reference_to_const_int = "<<reference_to_const_int<<endl;
This code compiles & executes with output :-
reference_to_const_int = 20
This is something strange in for me. As I know reference do not occupy memory & they are aliases to other variables. hence we cannot say
int& reference_to_int = 30;
The above statement shall not compile giving error :-
error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’
What exactly is happening in the "const int&" case? A full explanation is desired.
Kindly help.
Thanks
A temporary is created, and it's legal to bind a const reference to it, but illegal to bind it to a non-const one.
It's just like:
const int& reference_to_const_int = int(20); //LEGAL
int& reference_to_const_int = int(20); //ILLEGAL
A const reference extends the life of a temporary, that's why this works. It's just a rule of the language.
This behavior is easier to understand when we look at what happens when we bind a reference to a temporary object. If we write
const int& reference_to_const_int = 20; //A temporay object int(20) is created.
the compiler transforms above code into something like this:
int temp = 20;
const int& reference_to_const_int = temp;
If reference_to_const_int were not const, then we could assign a new value to reference_to_const_int. Doing so would not change literal 20 but would instead change temp, which is a temporary object and hence inaccessible.
Allowing only const references to be bound to values requiring temporaries avoids the problem entirely because a const reference is read-only.
Why do C++ allows const references to accept temporary objects or RVALUES (like literals)?
The most common places we see references are as function arguments or return values.
When a reference is used as a function argument, any modification to the reference inside the function will cause changes to the argument outside the function.
If function can expect/accept temporary objects or literals as inputs and if the function respects const-ness of the object, making the argument a const reference will allow the function to be used in all situations.
Temporary objects are always const, so if you don’t use a const reference, that argument won’t be accepted by the compiler.
void f(int&) {}
void g(const int&) {}
int main()
{
//f(1); //Error
g(1); //OK
}
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