프로그래밍 언어/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, 초기화 체크 등 |