November 23, 2020

Область видимости переменных

Область видимости определяет, в каком блоке кода можно использовать переменную. Продолжительность жизни (или «время жизни») определяет, где переменная создается и где уничтожается. Эти две концепции связаны между собой.

Глобальные переменные

Глобальные переменные определены в файле программы вне любой из функций и могут использоваться любой функцией.

int n = 5;
 
void print() {
    n++;
    cout << "n=" << n << endl;
}
 
int main() {
    print(); // n=6
    n++;
    cout << "n=" << n << endl; // n=7
}

Здесь переменная n является глобальной и доступна из любой функции. При этом любая функция может изменить ее значение.

Избегайте использования неконстантных глобальных переменных, насколько это возможно! Если же используете, то используйте их максимально разумно и осторожно.

Локальные переменные

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

int main() {
    int m = 4; // переменная m создается и инициализируется здесь
    { // начало вложенного блока
        double k = 5.0; // переменная k создается и инициализируется здесь
    } // k выходит из области видимости и уничтожается здесь
    
    // Переменная k не может быть использована здесь, так как она уже уничтожена!
} // переменная m выходит из области видимости и уничтожается здесь    

Сокрытие объектов

Переменная внутри вложенного блока может иметь то же имя, что и переменная внутри внешнего блока. Когда подобное случается, то переменная во вложенном (внутреннем) блоке «скрывает» внешнюю переменную. Это называется сокрытием объектов (или сокрытие имен):

int main() {
    int n = 10;
    {
        int n = 20;
        cout << "n=" << n << endl;  // n=20
    }
    cout << "n=" << n << endl;  // n=10
}

Сокрытие объектов — это то, чего, как правило, следует избегать, поскольку оно может быть довольно запутанным!

Статические переменные

Кроме автоматических есть особый тип локальных переменных - статические. Они определяются на уровне функций с помощью ключевого слова static. Если автоматические переменные определяются и инициализируются при каждом входе в функцию, то статические переменные инициализируются только один раз, а при последующих вызовах функции используется старое значение статической переменной.

void display() {
    static int i = 0;
    i++;
    cout << "i=" << i << " ";
}
 
int main() {
    display();
    display();
    display();
}
 
// Вывод: 1 2 3

Область видимости переменных

Переменные должны определяться в максимально ограниченной области видимости. Например, если переменная используется только внутри вложенного блока, то она и должна быть определена в нем.

Ограничивая область видимости, мы уменьшаем сложность программы, поскольку число активных переменных уменьшается. Таким образом, легче увидеть, где какие переменные используются. Переменная, определенная внутри блока, может использоваться только внутри этого же блока. Этим мы упрощаем понимание и логику программы.