Назначение указателей указателям с или без квалификаторов

Пока это компилируется:

char* p2c;
const char* p2cc = p2c; //fine

потому что в указанном типе lhs есть все определители остроконечного типа rh, это не так:

char** p2p2c;
const char** p2p2cc = p2p2c; //fail

но это делает:

const char * const * p2cp2cc = p2p2c; //fine

Почему именно это происходит?

Ответ 1

Это не работает:

char** p2p2c;
const char** p2p2cc = p2p2c; //fail

Если это разрешено, вам будет разрешено нарушить const-correctness:

const int k = 10;
int *p;
int **pp = &p;
int const **kpp = pp;     // Should this be allowed, if so:
*kpp = &k;                // fine, kpp promises not to change it
                          // yet this does p = &k;
                          // p made no such promise! this is a hidden const_cast!
*p = 5;

Если присваивание разрешено, вы должны включить настройку указателя неконстантного (промежуточного), чтобы ссылаться на постоянное значение, что может привести к поведению undefined неочевидным образом. Не разрешая эту операцию, система типов более безопасна.

но это делает:

const char * const * p2cp2cc = p2p2c; //fine

Это нормально, поскольку промежуточный указатель исправлен, невозможно reset промежуточный указатель ссылаться на объект const и нарушать const-correctness

Ответ 2

cdecl действительно помогает в таких случаях.

const char** p2p2cc = declare p2p2cc as pointer to pointer to const char

и

const char * const * p2cp2cc = declare p2cp2cc as pointer to const pointer to const char

Как вы можете видеть, вторая версия имеет внутренний И внешний указатель const, то есть он также не может изменять. Первая версия имеет указатель INNER const и внешнюю не константу, тем самым разбивая константы.

С другой стороны, это работает:

char** const p = p2p2c;