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’
Related
I was going through C++ primer, and I am confused in line 2
const int ci = 42; // we cannot change ci; const is top-leve
int i = ci; // ok: when we copy ci, its top-level const is ignore
As per me, we defined ci to be constant. Then we simply copy it in 'i'
How does the "top-level const is ignored" come into the picture?
Can someone explain what exactly is difference between top & low-level const?
The value stored in the variable defined as const int ci remains a constant for its entire lifetime. This means you could not change its value in future lines of code. (ie. You could not later write ci = 43;, the compiler would enforce the const and not allow this code to build.)
However, when copied its value to int i, you created a new variable named i. And i was not defined as const, so it is what we refer to as mutable, meaning the code that follows can change its value.
The top-level term is used by some people and is dragged in from script languages. I saw it used in some C++ primers in meaning that "object itself is const" while const int* p would be low-level const, i.e. referred object is const.
const int* p; // low-level const, a pointer to a const
int* const p = &i; // top-level const, pointer is const
This term is not officially defined and perhaps should avoided due to confusion it creates.
const int* const p = &ci; // top-level and low-level?
C++ by default creates and operates upon mutable data, so those terms have little value . If you initialize a non-const object with a const one, new copy is mutable unless this is a class type and there is an intentional code that does otherwise in user-defined constructor. Created object still will not be const unless declared so. Also C++ enjoys existence of const_cast conversion which would be an affront to languages like Clojure.
int main()
{
int n = 1;
int* const p = &n; // ok
*p = 2; // ok as expected.
p = 0; // error as expected.
int& const m = n;
// error: 'const' qualifier may not be
// applied to a reference
return 0;
}
Why no const reference in C++ just like const pointer?
What's the rationale behind the design?
References in C++ differ from pointers in several essential ways. One of the difference is:
Once a reference is created, it cannot be later made to reference another object; it cannot be reseated. This is often done with pointers.
It means Reference are like similar (see the link at the end of this answer) to const pointer (not pointer to a const!) in C++...
int a = 5;
int& m = a; // Behaves similar to int * const m = &a;
// See the link at the bottom for the differences between const pointer and reference.
and hence, you can't change/rebind them to point to some other address. So, you don't need a explicit const qualifier for a reference and that's why it is disallowed by the compiler.
See this link to learn Why are references not reseatable in C++?. I have copied the accepted answer of the above link:
The reason that C++ does not allow you to rebind references is given in Stroustrup's "Design and Evolution of C++" :
It is not possible to change what a reference refers to after initialization. That is, once a C++ reference is initialized it cannot be made to refer to a different object later; it cannot be re-bound. I had in the past been bitten by Algol68 references where r1=r2 can either assign through r1 to the object referred to or assign a new reference value to r1 (re-binding r1) depending on the type of r2. I wanted to avoid such problems in C++.
EDIT:
See this link for Difference between const pointer and reference? (Thanks to #M.M for pointing out the ambiguity in my statement).
Why no const reference in C++ just like const pointer?
References cannot be modified. Adding const qualification to non-modifiable entity would be meaningless and confusing.
Note that it is technically possible to apply const to a reference indirectly through a type alias or template type argument. Example:
T some_t;
using Ref = T&;
Ref const some_ref = some_t; // well-formed
Ref const type "collapses" into T&, and is same as unqualified Ref. I recommend to generally avoid creating type aliases for pointers and references, except for rare cases where they are conventional. Specifically, Container::reference type alias and similar are conventional.
int& const m = n;
IMHO because it's inherently constant by compiler nature, just
int n ;
n has ininherent constant reference
so as it is parsing codes it just determine to whichever place const qualifier is only allowed being there, by a compiler rule method for parsing, if not allowed then go to error/warning
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!
With pointers I can do this:
int a=1;
int b=2;
const int* cnstIntPtr = &a;
// (*cnstIntPtr)++ does not work, makes sense since value pointed to is constant
cnstIntPtr = &b; // works, makes sense
const int* const cnstIntCnstPtr = &a;
// (*cnstIntCnstPtr)++; does not work, makes sense since value pointed to is constant
// cnstIntCnstPtr = &b; does not work, makes sense since pointer is constant
but with references:
const int& cnstIntRef = a;
// cnstIntRef++; does not work, makes sense since const refers to value at address
// cnstIntRef = b; why does this not work? "expression must be modifiable lvalue"
const int& const cnstIntCnstRef = a;
//cnstIntCnstRef++; does not work, makes sense since const refers to value at address
//cnstIntCnstRef = b; does not work, makes sense since const refers to value at address
So why can't I reassign to a const reference when the const is supposed to be referring to the value at the address (by analogy with how pointers work). If this is in general not possible, why is that and what is the meaning of the second const in
const int& const cnstIntCnstRef?
// cnstIntRef = b; why does this not work? "expression must be modifiable lvalue"
For the same reason as why cnstIntRef++; doesn't work. cnstIntRef is reference to const, and therefore the the value may not be assigned to.
If this is in general not possible, why is that
It is indeed not possible.
References are different from pointers: They are dereferenced automatically. An assignment to a reference variable is an assignment to the referred object. Just as you understand that cnstIntRef++ is analogous to (*cnstIntPtr)++ , you must also understand that cnstIntRef = a is analogous to *cnstIntPtr = a.
As a consequence, there is no syntax to "reassign" a reference to refer to another object. A reference always refers to exactly one object throughout its entire lifetime.
what is the meaning of the second const in
const int& const cnstIntCnstRef?
It has no meaning because it is ill-formed. Unlike to pointers, qualifiers may not be applied to references; they may only be applied to the referred type.
then how do I deal with a std::vector<const int&>
You cannot deal with std::vector<const int&> because const int& is not a valid type for an element of std::vector. Vector requires the elements to be erasable. References are not erasable.
What I need to do is set the size of it, and later in the constructor body fill in the elements.
You can use a vector of pointers instead. Or vector of std::reference_wrapper if that's more convenient for template purposes.
push_back is out of the question since it messes up the references
push_back won't mess up references if you reserve first.
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