Перейти к содержимому
Теория · Переменные и типы · урок 4 из 10

const и constexpr

Некоторые значения программа задаёт один раз и больше не меняет: число попыток, длину суток в секундах, курс валюты на момент запуска. Если объявить такую переменную с const, случайно изменить её не даст компилятор:

C++
int main() {
    const int max_tries = 3;
    max_tries = 5;  // ✗
}
TEXT
error: cannot assign to variable 'max_tries' with const-qualified type 'const int'

Это ошибка компиляции, а не предупреждение: программа не соберётся, пока лишнее присваивание не уберут.

Только для чтения

const перед типом запрещает менять переменную после инициализации. Поэтому начальное значение у неё обязательно: const int max_tries; тоже не скомпилируется. Само значение может быть любым, в том числе вычисленным во время работы программы:

C++
#include <iostream>

int main() {
    int width = 4;
    const int area = width * width;
    width = 5;
    std::cout << area << ' ' << width << '\n';  // 16 5
}

area получила значение при инициализации и сохранила его, когда изменилась width. const относится к переменной, а не к значению. Копия const-переменной — обычная переменная, и её можно менять. Читателю const тоже помогает: значение такой переменной задано в одном месте — в объявлении.

Значение при компиляции

constexpr требует большего: значение должно быть известно уже при компиляции. Поэтому такую переменную инициализируют константой — например, литералом или выражением из литералов и других constexpr-переменных. const-переменная со значением, вычисленным во время работы программы, как area выше, для этого не подходит. Компилятор вычисляет такое выражение сам, и программа получает готовое число:

C++
#include <iostream>

int main() {
    constexpr int kSecondsPerHour = 60 * 60;
    constexpr int kSecondsPerDay = 24 * kSecondsPerHour;
    std::cout << kSecondsPerDay << '\n';  // 86400
}

Изменить constexpr-переменную тоже нельзя: constexpr включает в себя const. Если значение известно заранее, объявляйте переменную constexpr, а если оно появляется только во время работы — const. Имена constexpr-констант в курсе пишут в стиле kName, а const-переменные называют как обычные.

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

constexpr-переменную инициализируют значением, которое известно только во время работы программы:

C++
int main() {
    int width = 4;
    constexpr int area = width * width;  // ✗
    return area;
}
TEXT
error: constexpr variable 'area' must be initialized by a constant expression

width — обычная переменная: число 4 записано прямо в коде, но переменную можно изменить, поэтому константой её значение не считается. Объявите area как const: ей хватит значения, вычисленного во время работы. Другой способ — сделать constexpr и саму width: тогда width * width известно уже при компиляции.