← Назад к вопросам

Что такое ключевое слово static?

1.0 Junior🔥 231 комментариев
#Язык C++

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ключевое слово Static в C/C++

static — одно из самых многоплановых ключевых слов в C/C++. В зависимости от контекста оно имеет совершенно разные значения.

1. Static переменные в функции (Static Storage Duration)

При объявлении внутри функции static переменная сохраняет своё значение между вызовами функции. Инициализируется один раз при первом вызове.

void increment() {
    static int counter = 0;  // Инициализируется только один раз!
    counter++;
    std::cout << counter << std::endl;
}

int main() {
    increment();  // Выведет: 1
    increment();  // Выведет: 2
    increment();  // Выведет: 3
}

Где хранится? Static переменные находятся в сегменте данных (data segment), а не в стеке.

2. Static глобальные переменные (Internal Linkage)

При объявлении вне функции static ограничивает видимость переменной только текущим файлом. Эта переменная недоступна из других файлов (даже через extern).

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

void increment() {
    global_counter++;
}

int get_counter() {
    return global_counter;
}
// file2.cpp
extern int global_counter;  // ОШИБКА! Нельзя получить доступ

Зачем нужно? Для инкапсуляции и избегания конфликтов имён между файлами.

3. Static функции (Internal Linkage)

Функция, объявленная как static, видна только в текущем файле.

// file1.cpp
static void helper_function() {  // Приватная функция
    // ...
}

void public_function() {
    helper_function();
}

4. Static членские переменные класса

Принадлежит классу, а не объекту. Общая для всех экземпляров.

class Counter {
public:
    static int instance_count;  // Декларация
    
    Counter() {
        instance_count++;
    }
};

// Определение и инициализация
int Counter::instance_count = 0;

int main() {
    Counter c1, c2, c3;
    std::cout << Counter::instance_count << std::endl;  // Выведет: 3
    std::cout << c1.instance_count << std::endl;  // Также: 3
}

5. Static методы класса

Метод, принадлежащий классу, а не объекту. Не имеет доступа к this и нестатическим членам.

class Math {
public:
    static double pi() {
        return 3.14159265359;
    }
    
    static int add(int a, int b) {
        return a + b;
    }
};

int main() {
    std::cout << Math::pi() << std::endl;   // Правильно
    std::cout << Math::add(2, 3) << std::endl;  // Правильно
    
    Math m;
    std::cout << m.pi() << std::endl;  // Работает, но плохой стиль
}

6. Static локальные переменные в многопоточности (важно!)

В многопоточном коде static локальные переменные инициализируются только один раз, потокобезопасно.

#include <thread>
#include <iostream>

void lazy_initialization() {
    static int value = 0;  // Инициализируется один раз, потокобезопасно
    value++;
    std::cout << value << std::endl;
}

int main() {
    std::thread t1(lazy_initialization);
    std::thread t2(lazy_initialization);
    t1.join();
    t2.join();
}

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

КонтекстВидимостьСрок жизниИспользование
Static переменная в функцииФункцияДо конца программыСчётчики, кэши
Static глобальная переменнаяФайлДо конца программыСкрытие имён
Static функцияФайлДо конца программыВспомогательные функции
Static переменная классаКлассДо конца программыСчётчик экземпляров
Static метод классаКлассДо конца программыУтилиты, фабрики

Практический пример: Синглтон паттерн

class DatabaseConnection {
private:
    static DatabaseConnection* instance;
    
    DatabaseConnection() {
        // Конструктор приватный
    }
    
public:
    static DatabaseConnection* getInstance() {
        if (instance == nullptr) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
};

DatabaseConnection* DatabaseConnection::instance = nullptr;

int main() {
    auto db1 = DatabaseConnection::getInstance();
    auto db2 = DatabaseConnection::getInstance();
    
    // db1 == db2 (одни и те же объект)
}

Примечание: В C++11 есть более безопасный подход через локальную static переменную:

class DatabaseConnection {
public:
    static DatabaseConnection& getInstance() {
        static DatabaseConnection instance;  // Инициализируется один раз, потокобезопасно
        return instance;
    }
};

Типичные ошибки

// ❌ ОШИБКА: забыли инициализировать static переменную класса
class MyClass {
public:
    static int value;
};
// Линкер выдаст ошибку!

// ✅ ПРАВИЛЬНО:
class MyClass {
public:
    static int value;
};
int MyClass::value = 0;  // Определение и инициализация

Лучшие практики

  • Используй static функции и переменные для скрытия деталей реализации
  • Избегай глобальных static переменных (могут усложнить порядок инициализации)
  • Используй static методы класса для утилит и фабрик, а не глобальных функций
  • Для синглтонов используй локальную static переменную (C++11+)
  • Осторожно с многопоточностью: static локальные переменные потокобезопасны в C++11+