const T* и T* const
Указатель — бумажка с адресом дома. На такой бумажке можно запретить две разные вещи:
- менять что-то в доме: по бумажке можно прийти и посмотреть, но не трогать;
- переписывать саму бумажку: адрес на ней написан навсегда, хотя в доме менять можно.
Оба запрета в C++ пишут одним словом const. Переменная a в этой программе объявлена без const, и всё же изменить её через указатель p компилятор не даёт:
int main() {
int a = 1;
int b = 2;
const int* p = &a;
*p = 5; // ✗
p = &b;
return *p;
}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 запрещено и то и другое.
#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
}Давайте разберём пример по строкам:
const int* p = &a;— бумажка «только смотреть» с адресомa.p = &b;переписывает её: теперьpуказывает наb.int* const q = &a;— бумажка с адресомa, написанным навсегда.*q = 5;меняетaчерезq: это разрешено.- Программа печатает
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-переменной кладут в обычный указатель:
int main() {
const int limit = 10;
int* p = &limit; // ✗
return *p;
}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 и подпишись на канал — откроются все уроки.