0

I am reading C++ primer and I'm stuck on this topic. It is written that

int i=0;
const int ci=42; //const is top level.
const int *p2=&ci; //const is low level.
const int *const p3=p2; //rightmost const is top level,left one is low level. 
int *p=p3 //error.
p2=p3 //ok:p2 has the same low level constant qualification as p3.
int &r=ci; //error: can't bind an ordinary int to const int object
const int &r2=i; //ok:can bind const int to plain int.

Now if top level constants are ignored in last statement, then it should give an error, because the low level constant qualification of &r2 and i are not same. The why is the last staement correct??

  • I don't understand your question.. What are you confused about? – user253751 Jun 09 '16 at 04:38
  • 1
    The title of your question seems unrelated to the contents of the question. I don't see anything about copying objects in your question. – R Sahu Jun 09 '16 at 04:44
  • I am not getting the last two statements dealing with references. The rule i.e to ignore the top level constants doesn't seem to work here. – Naman Sharma Jun 09 '16 at 04:52
  • There are no top level constants in the last exemple. Moreover low level const qualification is not ignored, you are just creating a reference on a const object from a non-const objet, and this works fine (unless I miss something). See http://stackoverflow.com/a/7914580/5091340 for a clear explanation of top level constness. – yayg Jun 09 '16 at 05:21
  • `int &r=ci;` is rejected because `r` is declared as a reference to an `int` that can change but you're binding it to `const int ci` which is not allowed to change. However it's ok to go the other way. `const int &r2=i;` means `r2` is a reference to a `const int`. You're not allowed to change the value of `i` if you go through `r2`, but you can still change `i` itself. – John D Jun 09 '16 at 05:21
  • By your logic,its right! But if we take it as- While copying objects, top level constants are ignored while low level are not. Then ci has a top level constant and if we ignore that , the type of ci becomed int. while the type of reference is an integer.So it should work fine ? Or am I wrong because since reference is not an object, so the above logic doesn't work here. Where am i wrong? – Naman Sharma Jun 09 '16 at 05:35
  • You can have pointers which are `const` (must always point to same object) or not `const` (you can point it to another object). But references themselves are constant - once they are bound to an object, they are bound forever. That's why you don't see `const int & const r2 = i;` - the 2nd `const` is redundant. – John D Jun 09 '16 at 05:35
  • Can you give a link to the C++ primer? Just looking at top-level and low-level seems to over simplify the issue. I learned `const` from the viewpoint of making a promise. When you do an assignment (copy) is it possible to break any promises? If so, it's an error. But you need to careful about what exactly is being promised. – John D Jun 09 '16 at 06:54

2 Answers2

4

You're asking a billion questions in one, but I'll summarize.

  • These:

    int &r=ci; //error: can't bind an ordinary int to const int object
    const int &r2=i; //ok:can bind const int to plain int.
    

    Follow the rules of reference initialization. The left-hand side needs to have the same or greater than cv-qualification of the right-hand side.

  • These:

    const int *p2=&ci; //const is low level.
    const int *const p3=p2; //rightmost const is top level,left one is low level. 
    int *p=p3 //error.
    p2=p3 //ok:p2 has the same low level constant qualification as p3.
    

    Follow the rules of qualification conversions. Essentially they try to preserve const correctness. Which an assignment like p = p3 would certainly not do.

I think you'll have a much easier time comprehending the rules if you drop the "top-level" and "low-level" const stuff as they're clearly not helping you understand what's happening here.

0

When working through const declarations, you look backwards. Unfortunately it has one exception: const int is allowed for historical reasons, but it means the same as int const.

Below, the const "looks back" to the int so p points to an int which can't be changed.

int const * p; 

And here, the const "looks back" to the int * so p is not allowed to point to anything else, but what it points to now can be changed through p.

int i = 5; int j = 5;
int * const p = &i;
*p = 6;       // ok, you can still modify `i` through `p`
p = &j;       // error because you can't change what `p` points at

And here, p is a const pointer to a const int. p is not allowed to change and what it points to cannot be changed.

int i = 5; int j = 5
int const * const p = &i;
*p = 6;       // error, promised not to makes changes through `p`
p = &j;       // error `p` is stuck to `i`

When assigning one thing to another, the rule is that promises cannot be broken. int const is a promise that the int will never be changed. If you try this:

int const i = 5;
int * p = &i;      // error

and the compiler let you do it, you would then be able to break the promise that i would never change by doing this

*p = 6;

and now i will be changed from 5 to 6, breaking the promise that i will never change.

It's ok the other way round because you're not breaking any promises. In this case, you're only promising not to change i when you access it through the pointer p

int i = 5;
int const * p = &i;
*p = 6;             // error, because we promised not to change `i` through `p`
i = 6;              // ok, because `i` itself is not const

const is important as a built-in safety check. The compiler will give you an error if something you declare as const is changed. You can declare methods of a class to be const and that is a promise that no data in the class will be changed by that method. It's easy to forget and later modify that method to change something in the class but the compiler will remind you.

It is also important for optimisation. If the compiler knows that something is const it can make a lot of simplifying assumptions to speed up the code.

John D
  • 1,627
  • 1
  • 11
  • 10