프로그래밍 언어/C++

C++ static - 2. static 변수의 종류와 특징 (2.2. 지역(static local) 변수)

개발_노트 2025. 3. 25. 20:05

 

✅ 2.2. 지역(static local) 변수

🔹 일반 지역 변수와의 생명주기 차이

항목 일반 지역 변수 static 지역 변수
선언 위치 함수 또는 블록 내부 동일
메모리 위치 스택(Stack) 데이터 영역(Data Segment)
생명주기 함수 호출 시 생성 → 종료 시 소멸 프로그램 종료 시까지 유지
값 유지 여부 호출 시마다 초기화 초기화 한 번, 값 유지됨

📌 static 지역 변수는 한 번만 초기화되고, 그 이후 함수가 호출될 때도 값이 유지됩니다.


🔹 초기화 시점과 C++11 이후의 변화

  • static 지역 변수는 해당 함수에 처음 진입할 때 한 번만 초기화됩니다.
  • 이 초기화 시점은 런타임 중 최초 실행 시점이며, 선언과 동시에 초기화되더라도 실제로는 사용되기 전까지 초기화되지 않습니다.

🧠 C++11 이후의 특징:

  • C++11부터는 지역 static 변수의 초기화가 스레드 안전하게 보장됩니다.
  • 여러 스레드가 동시에 초기화에 접근하더라도 단 하나의 스레드만 초기화를 진행하고, 나머지는 기다립니다.

🔹 다중 스레드 환경에서의 고려사항

  • static 지역 변수 초기화 자체는 C++11 이후 스레드 안전(thread-safe) 이지만,
  • 초기화 이후 해당 변수에 여러 스레드가 동시에 접근하여 값을 수정하면 여전히 race condition이 발생할 수 있습니다.

💡 해결책:

  • 초기화 이후에도 동시 접근이 있다면, std::mutex 또는 원자적 연산(std::atomic)을 사용해 동기화 필요

🔹 함수가 여러 번 호출되어도 유지되는 값

  • static 지역 변수는 이전 호출에서의 상태를 기억할 수 있기 때문에,
  • 상태 저장, 호출 횟수 누적, 1회 초기화 체크 등에 자주 사용됩니다.

🔹 예시 1: 호출 횟수 누적 함수

#include <iostream>

void countCalls() {
    static int count = 0;
    count++;
    std::cout << "Function called " << count << " times." << std::endl;
}

int main() {
    countCalls();  // Function called 1 times.
    countCalls();  // Function called 2 times.
    countCalls();  // Function called 3 times.
}

🔍 static을 제거하면 항상 1만 출력됩니다.
이처럼 static 지역 변수는 함수 내부에서 상태를 유지하는 가장 간단한 방법입니다.


🔹 예시 2: 1회 초기화 플래그 활용

void doSomethingOnce() {
    static bool initialized = false;
    if (!initialized) {
        std::cout << "초기화 수행 중...\n";
        initialized = true;
    }
    std::cout << "작업 실행\n";
}

🔍 자주 호출되는 함수 안에서 초기화 코드만 딱 한 번 실행하고 싶을 때 유용합니다.


🔹 예시 3: Lazy Initialization

#include <string>
#include <iostream>

const std::string& getCachedString() {
    static std::string value = []() {
        std::cout << "복잡한 초기화 중...\n";
        return std::string("Ready!");
    }();
    return value;
}

🔍 고비용 객체를 실제로 필요해지기 전까지 초기화하지 않도록 하는 대표적인 패턴입니다.
특히 성능 최적화, 리소스 절약이 필요한 상황에서 유용합니다.


✅ 요약

항목 설명
위치 함수 내부 또는 블록 내부
메모리 영역 데이터 세그먼트 (Data/BSS)
생명주기 프로그램 종료 시까지 지속
초기화 시점 최초 실행 시 한 번만
스레드 안전성 C++11 이후 초기화 시점은 안전함
주의 사항 초기화 이후 동시 수정 시에는 동기화 필요
활용 사례 호출 누적, 상태 기억, Lazy Initialization, 초기화 체크 등