Why isn't it legal to convert "pointer to pointer to non-const" to a "pointer to pointer to const"
Asked Answered
V

5

46

It is legal to convert a pointer-to-non-const to a pointer-to-const.

Then why isn't it legal to convert a pointer to pointer to non-const to a pointer to pointer to const?

E.g., why is the following code illegal:

char *s1 = 0;
const char *s2 = s1; // OK...
char *a[MAX]; // aka char **
const char **ps = a; // error!
Vela answered 8/2, 2010 at 10:33 Comment(8)
I suggest you define "a" as "char **", your example will be clearer without an unnecessary array.Nadinenadir
*a[MAX] does not result in char** but actually char** const. Also: parashift.com/c++-faq-lite/const-correctness.html#faq-18.17.Phosphorite
Yes but his question applies as well when a is char**.Nadinenadir
you are changing the constness. These types are not the same and your compiler complains about it. With an explicit cast you tell the compiler you know what you are doing.Chiseler
I do now the types are different. Pointer to constant and ordinary pointer are different as well, however you're allowed to assign pointer to constant a value of ordinary pointer. I am aware of explicit casts and avoid using those unless absolutely necessary.Bascom
below explanation is pretty good actually.Chiseler
@MaxShawabkeh it decays to char**, there is no const .Dingo
Looks like a question I answered was merged w/ this one, see my answer below which is now part of your question.Gur
L
41

From the standard:

const char c = 'c';
char* pc;
const char** pcc = &pc;   // not allowed
*pcc = &c;
*pc = 'C';                // would allow to modify a const object
Lilywhite answered 8/2, 2010 at 10:41 Comment(0)
M
26

Ignoring your code and answering the principle of your question, see this entry from the comp.lang.c FAQ: Why can't I pass a char ** to a function which expects a const char **?

The reason that you cannot assign a char ** value to a const char ** pointer is somewhat obscure. Given that the const qualifier exists at all, the compiler would like to help you keep your promises not to modify const values. That's why you can assign a char * to a const char *, but not the other way around: it's clearly safe to "add" const-ness to a simple pointer, but it would be dangerous to take it away. However, suppose you performed the following more complicated series of assignments:

const char c = 'x';    /* 1 */
char *p1;              /* 2 */
const char **p2 = &p1; /* 3 */
*p2 = &c;              /* 4 */
*p1 = 'X';             /* 5 */

In line 3, we assign a char ** to a const char **. (The compiler should complain.) In line 4, we assign a const char * to a const char *; this is clearly legal. In line 5, we modify what a char * points to--this is supposed to be legal. However, p1 ends up pointing to c, which is const. This came about in line 4, because *p2 was really p1. This was set up in line 3, which is an assignment of a form that is disallowed, and this is exactly why line 3 is disallowed.

And as your question is tagged C++ and not C, it even explains what const qualifiers to use instead:

(C++ has more complicated rules for assigning const-qualified pointers which let you make more kinds of assignments without incurring warnings, but still protect against inadvertent attempts to modify const values. C++ would still not allow assigning a char ** to a const char **, but it would let you get away with assigning a char ** to a const char * const *.)

Macerate answered 8/2, 2010 at 10:52 Comment(1)
And from the better-known C++ faq: parashift.com/c++-faq-lite/const-correctness.html#faq-18.17Saba
S
11

Just since nobody has posted the solution, here:

char *s1 = 0;
const char *s2 = s1; // OK...
char *a[MAX]; // aka char **
const char * const*ps = a; // no error!

(http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17 for why)

Saba answered 8/2, 2010 at 11:13 Comment(3)
It should be noted that it won't work for C, only C++.Involuted
The question isn't marked c. Is there any other reason for the downvote?Saba
Just use const_cast if you want to bypass const-correctness. This solution is overly complicated.Dasilva
G
10

The C++11 draft standard explains this in a note in section 4.4 which says:

[ Note: if a program could assign a pointer of type T** to a pointer of type const T** (that is, if line #1 below were allowed), a program could inadvertently modify a const object (as it is done on line #2). For example,

int main() {
const char c = 'c';
char* pc;
const char** pcc = &pc; // #1: not allowed
*pcc = &c;
*pc = 'C'; // #2: modifies a const object
}

—end note ]

An interesting related question is Given int **p1 and const int **p2 is p1 == p2 well formed?.

Note the C++ FAQ also has an explanation for this but I like the explanation from the standard better.

The conforming text that goes with the note is as follows:

A conversion can add cv-qualifiers at levels other than the first in multi-level pointers, subject to the following rules:56

Two pointer types T1 and T2 are similar if there exists a type T and integer n > 0 such that:

T1 is cv1,0 pointer to cv1,1 pointer to · · · cv1,n−1 pointer to cv1,n T

and

T2 is cv2,0 pointer to cv2,1 pointer to · · · cv2,n−1 pointer to cv2,n T

where each cvi,j is const, volatile, const volatile, or nothing. The n-tuple of cv-qualifiers after the first in a pointer type, e.g., cv1,1, cv1,2, · · · , cv1,n in the pointer type T1, is called the cv-qualification signature of the pointer type. An expression of type T1 can be converted to type T2 if and only if the following conditions are satisfied:

  • the pointer types are similar.
  • for every j > 0, if const is in cv1,j then const is in cv2,j , and similarly for volatile.
  • if the cv1,j and cv2,j are different, then const is in every cv2,k for 0 < k < j.
Gur answered 24/3, 2015 at 18:20 Comment(2)
Thanks a lot. After reading your answer for a couple of times I finally got it!Bascom
@AntonTugolukov looks like you question was merged w/ this current oneGur
I
6

There are two rules here to note:

  • There are no implicit casts between T* and U* if T and U are different types.
  • You can cast T* to T const * implicitly. ("pointer to T" can be cast to "pointer to const T"). In C++ if T is also pointer then this rule can be applied to it as well (chaining).

So for example:

char** means: pointer to pointer to char.

And const char** means: pointer to pointer to const char.

Since pointer to char and pointer to const char are different types that don't differ only in const-ness, so the cast is not allowed. The correct type to cast to should be const pointer to char.

So to remain const correct, you must add the const keyword starting from the rightmost asterisk.

So char** can be cast to char * const * and can be cast to const char * const * too.

This chaining is C++ only. In C this chaining doesn't work, so in that language you cannot cast more than one levels of pointers const correctly.

Involuted answered 26/6, 2014 at 15:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.