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

Область видимости и время жизни

Представьте, что каждый блок программы — комната со своими коробками. Коробку, которую поставили в комнате, видно только в ней: за дверью её уже не найти по наклейке. В C++ стенами комнаты служат фигурные скобки. Имя переменной, объявленной внутри них, действует только до закрывающей скобки. Снаружи его нет:

C++
#include <iostream>

int main() {
    int total = 0;
    {
        int bonus = 10;
        total = total + bonus;
    }
    std::cout << total + bonus << '\n';  // ✗
}
TEXT
error: use of undeclared identifier 'bonus'

Часть программы, где имя переменной можно использовать, называют её областью видимости. Она начинается с объявления и заканчивается на закрывающей скобке блока — фрагмента кода в фигурных скобках. Тело функции тоже блок. Поэтому переменные с одним именем в разных функциях — это разные переменные.

Сокрытие имени

Во вложенном блоке можно объявить переменную с тем же именем, что и снаружи. Это новая переменная, как коробка с той же наклейкой, поставленная во внутренней комнате: до конца блока имя обозначает её, а внешняя скрыта. Такое сокрытие заканчивается на закрывающей скобке, и внешняя переменная снова видна с прежним значением:

C++
#include <iostream>

int main() {
    int score = 5;
    {
        int score = 100;
        std::cout << score << '\n';  // 100
    }
    std::cout << score << '\n';  // 5
}

Время жизни

Время жизни — срок, в течение которого переменная существует в памяти. Область видимости — свойство имени в тексте программы, а время жизни — свойство самой переменной во время работы. Обычная переменная внутри функции создаётся, когда выполнение доходит до объявления, и уничтожается в конце блока. При следующем вызове функции она создаётся заново. Это как коробка, которую выбрасывают, когда выходят из комнаты, а при следующем визите приносят новую.

Переменная со словом static живёт до конца программы: её коробка остаётся на полке в комнате, и при каждом визите содержимое на месте. Её инициализируют один раз, а не при каждом вызове, и между вызовами она хранит значение:

C++
#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. Что выведет функция со static-счётчиком, часто спрашивают на собеседовании.

Пройдите эту программу по шагам и следите за рамками: visits лежит в рамке static и переживает каждый вызов, а steps появляется и исчезает вместе с visit.

Вживуюstatic: что переживает вызовшаг 1 из 10

visits уже существует и равна 0, хотя visit ещё не вызывали

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

Хотели изменить внешнюю переменную внутри блока, но по привычке написали тип ещё раз:

C++
#include <iostream>

int main() {
    int total = 0;
    {
        int bonus = 10;
        int total = bonus;  // ✗
        std::cout << total << '\n';  // 10
    }
    std::cout << total << '\n';  // 0
}

Строка с int объявляет новую переменную, которая скрывает внешнюю total, и внешняя остаётся равной 0. Компилятор не сообщает ни об ошибке, ни о предупреждении. Чтобы изменить внешнюю переменную, нужно присваивание без типа: total = total + bonus;.

Главное

  • Область видимости — часть программы, где можно использовать имя: от объявления до закрывающей скобки блока.
  • Переменная с тем же именем во вложенном блоке скрывает внешнюю до конца блока, а внешняя сохраняет прежнее значение.
  • Обычная переменная в функции создаётся заново при каждом вызове, а static инициализируется один раз и хранит значение между вызовами.
  • static меняет время жизни, но не область видимости.

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

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

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