Как static влияет на глобальные/локальные переменные?cplus-45

Ключевое слово static в C/C++ меняет время жизни и область видимости переменных в зависимости от контекста использования. Рассмотрим его поведение для разных типов переменных.

1. Static для глобальных переменных

// file.cpp
static int globalVar = 42;  // static глобальная переменная

Эффекты:

  • Линковка: ограничивает область видимости файлом, где объявлена
  • Доступность: не видна в других единицах трансляции (internal linkage)
  • Время жизни: существует всю работу программы

Пример проблемы без static:

// file1.cpp
int sharedVar = 10;  // Будет конфликт при линковке

// file2.cpp
int sharedVar = 20;  // Ошибка: multiple definition

Решение с static:

// file1.cpp
static int localToFile1 = 10;  // Видна только в file1.cpp

// file2.cpp
static int localToFile2 = 20;  // Видна только в file2.cpp

2. Static для локальных переменных

void func() {
    static int counter = 0;  // static локальная переменная
    counter++;
}

Эффекты:

  • Время жизни: сохраняет значение между вызовами функции
  • Инициализация: выполняется только один раз при первом вызове
  • Память: размещается в статической памяти, а не на стеке

Пример использования:

void callCounter() {
    static int calls = 0;
    std::cout << "Функция вызвана " << ++calls << " раз\n";
}

3. Static для членов класса

class MyClass {
public:
    static int classVar;  // Статическая переменная класса
};

Эффекты:

  • Общая память: одна на все экземпляры класса
  • Доступ: можно обращаться без создания объекта
  • Инициализация: должна быть определена вне класса
int MyClass::classVar = 0;  // Определение static-переменной

Сравнительная таблица

ХарактеристикаГлобальный staticЛокальный staticЧлен класса static
Время жизниВся программаВся программаВся программа
Область видимостиФайлФункцияКласс
ПамятьСтатическаяСтатическаяСтатическая
ИнициализацияОдин разПри первом вызовеОдин раз

Практические примеры

Паттерн Singleton (использование static):

class Singleton {
public:
    static Singleton& getInstance() {
        static Singleton instance;  // Гарантирует единственность
        return instance;
    }
private:
    Singleton() {}  // Приватный конструктор
};

Счетчик экземпляров класса:

class Widget {
public:
    Widget() { ++count; }
    ```Widget() { --count; }
    static int getCount() { return count; }
private:
    static int count;  // Общий для всех экземпляров
};
int Widget::count = 0;  // Определение

Основные ошибки

  1. Неопределение static-члена класса
    Забывают вынести определение за пределы класса

  2. Предположение о потокобезопасности
    static локальные переменные не всегда thread-safe

  3. Использование static для временных данных
    Неоправданное увеличение времени жизни переменных

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