Перейти к содержимому
Теория · Ссылки и указатели · урок 6 из 9

const T* и T* const

Указатель — бумажка с адресом дома. На такой бумажке можно запретить две разные вещи:

  • менять что-то в доме: по бумажке можно прийти и посмотреть, но не трогать;
  • переписывать саму бумажку: адрес на ней написан навсегда, хотя в доме менять можно.

Оба запрета в C++ пишут одним словом const. Переменная a в этой программе объявлена без const, и всё же изменить её через указатель p компилятор не даёт:

C++
int main() {
    int a = 1;
    int b = 2;
    const int* p = &a;
    *p = 5;  // ✗
    p = &b;
    return *p;
}
TEXT
error: read-only variable is not assignable

Ошибка только в строке *p = 5;, а строка p = &b; компилируется. Что запрещает const в объявлении указателя, зависит от того, где стоит сам const.

Указатель на константу

const int* p — указатель на константу. Это бумажка с пометкой «только смотреть»:

  • значение через p можно читать, но нельзя менять;
  • указывать p может и на переменную без const: запрет действует только на запись через p, а a = 5; по-прежнему работает;
  • сам p — обычная переменная, поэтому его можно перенаправить, как в строке p = &b;.

Функция, которая только читает числа по указателю, объявляет параметр как const int* data. Так она обещает не менять числа вызывающего кода: случайную запись вроде data[0] = 0; в теле функции компилятор остановит той же ошибкой, что и *p = 5;.

Константный указатель

Если const стоит после *, постоянным становится сам указатель. int* const q — константный указатель. Это бумажка, на которой адрес написан навсегда:

  • перенаправить q нельзя, поэтому инициализируют его сразу;
  • значение через q менять можно.

В const int* const r запрещено и то и другое.

C++
#include <iostream>

int main() {
    int a = 1;
    int b = 2;
    const int* p = &a;
    p = &b;
    int* const q = &a;
    *q = 5;
    std::cout << *p << ' ' << a << '\n';  // 2 5
}

Давайте разберём пример по строкам:

  1. const int* p = &a; — бумажка «только смотреть» с адресом a.
  2. p = &b; переписывает её: теперь p указывает на b.
  3. int* const q = &a; — бумажка с адресом a, написанным навсегда.
  4. *q = 5; меняет a через q: это разрешено.
  5. Программа печатает 2 5: *p читает b, а в a теперь 5.

Где стоит const

Всё решает место const относительно *: слева от звёздочки он относится к значению, а справа — к самому указателю. Поэтому int const* p значит то же, что const int* p.

Объявление удобно читать справа налево, начиная с имени:

  • int* const q — «q — константный указатель на int»;
  • const int* p — «p — указатель на константный int».

Частая ошибка

Адрес const-переменной кладут в обычный указатель:

C++
int main() {
    const int limit = 10;
    int* p = &limit;  // ✗
    return *p;
}
TEXT
error: cannot initialize a variable of type 'int *' with an rvalue of type 'const int *'

Через int* значение limit можно было бы изменить, поэтому компилятор запрещает такую инициализацию. Объявите указатель как const int* p = &limit;.

Главное

  • const int* p запрещает менять значение через p, но p можно перенаправить.
  • int* const q запрещает перенаправлять q, но значение через него менять можно.
  • const слева от * относится к значению, справа — к самому указателю.
  • Параметр const int* data обещает, что функция только читает числа.

Подпишись, чтобы пройти курс

Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.

Войти другим способом