0

[Note: I saw another question asking about the same section in the same book, but for different reasons]
Reading through the C++ primer book and was going through the section "top-level consts". Here it writes that:

The distinction between top-level and low-level matters when we copy an object. When we copy an object, top-level consts are ignored
When we copy an object, both objects must have the same low-level const qualification...

This I understood but I went ahead and manipulated an example given in the book multiple times to further my understanding with different scenarios. The code below is one such scenario:

int i = 5;
int *p = &i;
const int *const ptr = p;
p = ptr;

I had hypothesised before I ran the program that, Line 4 would be legal. However, intellisense instead threw me this error:

A value of type "const int *" cannot be assigned to an entity of type "int *"

Now I've done other things like *p = *ptr (which was legal), ptr = p (which would obviously be illegal) and changed the object i to const (which would henceforth require me to change p and satisfy the condition that copying an object must have the same low-level const). And in all cases, I've understood why.
But not for this scenario. Can someone explain why this is illegal?

Doobius
  • 127
  • 4
  • `ptr` might point to a `const int`. You wouldn't want a non-const `int*` to point to a `const int`. – François Andrieux Dec 11 '20 at 16:10
  • The classic example is something like this: `char * p = "hello world"` (used to be legal code) and then `p[0] = 'y';`. String Literal "hello world" may be in read only storage and writing to unwritable storage with `p[0] = 'y';` is bad idea. – user4581301 Dec 11 '20 at 16:15
  • @user4581301: `char * p = "hello world";` still is legal in C, it's just undefined behavior if you modify the `char`s, so it has to be treated as "effectively `const`". C++ made literals actually have `const char` data officially at least. – ShadowRanger Dec 11 '20 at 16:26

1 Answers1

3

First consider this example:

void foo(const int* p) {
     *x = 1;  // Error ! x is pointer to const
}

int x = 42;
foo(&x);

x is not const. Nevertheless, inside foo you are not allowed to modify its value via the const int* p, because it is a pointer to a const int. Having a pointer to const int does not imply that the int pointed to is actually const. It only means: You are not allowed to modify the int via that pointer.

The compiler does not consider what pointer you actually pass to see that *x = 1; is not allowed inside foo.

An int * on the other hand, does allow to modify the pointed to int. Now consider this:

 const int x = 42;
 const int* p = &x;
  
 int* p2 = p;  // Error ! why? 
 *p2 = 0;      // <- because of this

If you were allowed to assign the const int* to a int* this would create a hole in const correctness, because a int* does allow you to modify the pointee.

The top level const in

 const int* const p3 = &x;

refers to the pointer itself. You cannot modify the pointer. While you can modify this one:

 const int* p4;
 p4 = &x;
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185