auto, область видимости и время жизни
Имя переменной, объявленной внутри фигурных скобок, действует только до закрывающей скобки. Снаружи его нет:
#include <iostream>
int main() {
int total = 0;
{
int bonus = 10;
total = total + bonus;
}
std::cout << total + bonus << '\n'; // ✗
}error: use of undeclared identifier 'bonus'Часть программы, где имя переменной можно использовать, называют её областью видимости (scope). Она начинается с объявления и заканчивается на закрывающей скобке блока — фрагмента кода в фигурных скобках. Тело функции — тоже блок, поэтому переменные с одним именем в разных функциях — разные переменные.
Переменная, объявленная вне всех функций, — глобальная: её имя видно от объявления до конца файла, а живёт она до конца программы.
Сокрытие имени
Во вложенном блоке можно объявить переменную с тем же именем, что и снаружи. Это новая переменная: до конца блока имя обозначает её, а внешняя скрыта. Такое сокрытие (shadowing) заканчивается на закрывающей скобке, и внешняя переменная снова видна с прежним значением:
#include <iostream>
int main() {
int score = 5;
{
int score = 100;
std::cout << score << '\n'; // 100
}
std::cout << score << '\n'; // 5
}Время жизни
Время жизни (lifetime) — срок, в течение которого переменная существует в памяти. Область видимости — свойство имени в тексте программы, а время жизни — свойство самой переменной во время работы. Обычная переменная внутри функции создаётся, когда выполнение доходит до объявления, и уничтожается в конце блока. При следующем вызове функции она создаётся заново.
Переменная со словом static живёт до конца программы. Её инициализируют один раз, а не при каждом вызове, и между вызовами она хранит значение:
#include <iostream>
void visit() {
static int visits = 0;
int steps = 0;
visits = visits + 1;
steps = steps + 1;
std::cout << visits << ' ' << steps << '\n';
}
int main() {
visit(); // 1 1
visit(); // 2 1
visit(); // 3 1
}steps при каждом вызове начинается с 0, а visits продолжает счёт. static меняет только время жизни: видна visits по-прежнему лишь внутри visit.
Тип из начального значения
Вместо типа можно написать auto, и тогда компилятор выведет тип из начального значения. Он совпадает с типом литерала: auto count = 10; даёт int, а auto price = 2.5; — double. Для auto ratio = 2.5f; это float. Поэтому без начального значения auto не работает: auto total; не скомпилируется.
Частая ошибка
Переменную для дробной суммы объявили через auto с начальным значением 0:
#include <iostream>
int main() {
auto total = 0; // ✗
total = total + 2.5;
std::cout << total << '\n'; // 2
}Литерал 0 — это int, поэтому total тоже получает тип int. При присваивании 0 + 2.5 превращается в 2, а компилятор молчит. Исправление — литерал нужного типа: auto total = 0.0;.