Правила для конвертации между типами указателей, где cv-квалификаторы являются единственным отличием

Этот вопрос конкретно относится к C ++ 98, но не стесняйтесь вносить любую полезную информацию относительно новых стандартов, если хотите.

Если вы знаете ответ и хотите пропустить остальное, короткое & сладкое из этого:

int **w;
int volatile*     *x = w; // error
int volatile*const*y = w; // OK
int const   *const*z = w; // OK

Почему бы const быть необходимым справа от volatile в декларации y? Какое возможное зло может совершить кто-то, если декларация x были разрешены?

В разделе 4.4.4 стандарта говорится:

Конверсия может добавить cv-квалификаторы на уровнях, отличных от первого в многоуровневых указателях действуют следующие правила:

Два типа указателя T1 & Т2 являются аналогичный если существует тип T и целое число N > 0 такое что:

  • T1 — от CV10 до CV11 от … до CV1N T
  • T2 — от CV20 до CV21 от … до CV2N T

… где каждый CVij является const, volatile, const volatile или ничего. N-кортеж cv-квалификаторов после первый тип указателя, например, CV11, CV12, …, CV1N в типе указателя T1, называется квалификационная подпись типа указателя. Выражение типа T1 может быть преобразовано в тип T2 тогда и только тогда выполняются следующие условия:

  1. типы указателей похожи
  2. для каждого J > 0, если const находится в CV1j, то const находится в CV2j, и аналогично для volatile.
  3. если CV1j и CV2j разные, то const есть в каждом CV2k для 0 < К < J

… после чего он продолжает приводить пример для назначения ** к const**, акцент выше мое, курсив из документа.

Поместив это в код:

 int CV13* CV12* CV11* CV10 b1;
int CV23* CV22* CV21* CV20 b2 = b1;

Я немного нечеткий в некоторых деталях … так что вот некоторые вопросы или потенциально ошибочные наблюдения:

1) это говорит at levels other than the first; это не уточняется дальше, но CV20 может быть любым действительным классификатором CV.

2) 3-е правило внизу говорит, добавляет ли T2 либо const ИЛИ ЖЕ volatile на уровне jтогда уровни 1 ... j-1 должен быть постоянным (или терпеть гнев). Далее количество звездочек отличается от числа наверху, чтобы подчеркнуть то, что говорит 3-е правило:

int *****w;
int **volatile*     *     *x = w; // error
int **volatile*const*const*y = w; // OK
int **const   *const*const*z = w; // OK

Я понимаю зачем это нужно для zно почему с y? Вот пример того, как выглядит пример в 4.4.4, модифицированный для изменчивого случая:

void f( int **x ) {
int volatile**y = x; // not allowed
// do some evil here
}

Какое зло может быть помещено туда?

1

Решение

(Примечание: «Этот вопрос конкретно относится к C ++ 98», но положение дел одинаково во всех версиях Стандарта, в прошлом и настоящем (и в будущем, я бы даже поспорил), потому что в основном это касается правильности и предотвращения констант). кодеры от открытия дыры в системе типов.)

В качестве стандарта используется общий термин «CV-классификаторы«Мне легче понять, если рассуждать только с помощью»const«(нет»volatile«) [но см. ниже ниже пример с volatile]. «C ++ FAQ Lite» имеет связанную запись: Почему я получаю ошибку при конвертации Foo**Foo const**?

По сути, разрешение преобразования позволит вам молча изменить Const T (через указатель на не-const T):

int const theAnswer = 42;
int* p = 0;  // int* p = &theAnswer; is not allowed of course...
int** pp = &p;
int const** ppc = pp;  // <-- Error, but imagine this were allowed...
*ppc = &theAnswer;  // &theAnswer is `int const*` and *ppc is `int const*` too,
// but it's also doing *pp = &theAnswer; i.e. p = &theAnswer;
*p = 999;  // I.e. theAnswer = 999; => modifying a const int!

Но, добавив «первый уровень» constконверсия int const* const* pcpc = pp; допустимо, потому что компилятор будет препятствовать вам делать *pcpc = &theAnswer; потом (потому что *pcpc является const).


Редактировать: Что касается volatile, проблема, возможно, менее очевидна, чем с const, но разрешение на преобразование позволит вам молча неверно получить доступ (чтение или запись) к летучий Т, как будто это было не изменчивый (через указатель на не-летучий Т):

extern int volatile externTimer;
int* p = 0;  // int* p = &externTimer; is not allowed...
int** pp = &p;
int volatile** ppv = pp;  // <-- Error, but imagine this were allowed...
*ppv = &externTimer;  // &externTimer is `int volatile*` and *ppv too,
// but it's also doing *pp = &externTimer; i.e. p = &externTimer;
int a1 = externTimer;  // First read
int a2 = externTimer;  // Second read, mandatory: the value may have changed externally
int b1 = *p;  // First read
int b2 = *p;  // Second read? may be optimized out! because *p is not volatile

Но, добавив «первый уровень» constконверсия int volatile* const* pcpv = pp; допустимо, потому что компилятор будет препятствовать вам делать *pcpv = &externTimer; потом (потому что *pcpv является const).

2

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector