나만의 작은 도서관
[C++] 탐구 일지 #3. 정적 변수(static 키워드) 본문
static이 붙은 변수, 정적 변수
변수는 자신이 정의된 범위(중괄호로 표현됨)를 벗어나면 파괴된다. 즉, 변수가 선언된 중괄호를 벗어나는 순간, 변수의 생명 주기가 끝나면서 사라지게 된다.
하지만 변수가 static이 붙은 정적 변수라면 자신이 선언된 범위를 벗어날 때 사라지는 것이 아닌 프로그램이 종료될 때 사라진다.
아래 코드를 통해 정적 변수가 범위를 벗어나도 값이 유지되어 함수를 호출할 때마다 증가하는 것을 볼 수 있다.
+) 참고로 함수 내에 정적 변수가 존재할 경우, 정적 변수의 초기화는 함수가 처음 호출될때 단 한 번만 이루어진다.
#include <iostream>
using namespace std;
void func1(){
static int n = 0; // func1() 최초 호출 시에만 실행(초기화 코드)
cout << n << '\n';
n++;
}
int main()
{
func1(); // 0
func1(); // 1
func1(); // 2
return 0;
}
자동 초기화가 된다
정적 변수는 기본값으로 자동 초기화되는 변수이다. 따라서 따로 초기화하지 않고 선언만 해도 자동으로 초기화된다.
static int x; // x는 0으로 자동 초기화.
정적 변수는 데이터 영역에 저장된다
지역 변수는 기본적으로 프로세스 메모리 구조 중, 스택 메모리에 저장된다. 하지만 지역 변수에 static이 붙는 순간 정적 변수로 취급되어 스택 메모리가 아닌 데이터 영역(Data Segment)에 저장된다. 아래 코드처럼 정적 변수의 주소값이 지역 변수의 주소값과 크게 다르다는 것을 알 수 있다.
#include <iostream>
using namespace std;
int main()
{
int var1 = 3;
int var2 = 3;
static int staticVar = 3;
cout << &var1 <<'\n'; // 0x61fe1c (Stack 메모리 영역)
cout << &var2 <<'\n'; // 0x61fe18 (Stack 메모리 영역)
cout << &staticVar <<'\n'; // 0x403010 (Data Segment 메모리 영역)
return 0;
}
클래스와 static
static을 클래스 내부에 존재하는 멤버 변수 또는 멤버 함수에 사용할 수 있다.
정적 멤버 변수
static을 멤버 변수에 사용할 경우, 해당 변수는 클래스의 모든 객체들이 '공유'하는 변수로써, 각 객체 별로 따로 존재하는 멤버 변수들과 다르게 '단 하나의' 정적 멤버 변수를 사용하게 된다.
이때 주의할 점은, 일반 멤버 변수와 달리, 정적 멤버 변수는 클래스 내부에서 초기화하는 C++11부터 지원되는 인클래스 멤버 초기화(in-class member initialization)가 불가능하므로 클래스 외부에서 정의 및 초기화해야 한다.
+) 정적 멤버 변수는 모든 객체가 공유하는 변수이므로 클래스를 통해 접근하는 것이 올바른 방식이지만, 객체에서 접근할 수는 있다. (권장하지는 않는다.)
#include <iostream>
using namespace std;
class MyClass {
public:
int x = -1;
static int staticVar;
// static int staticVar = 10; // error: in-class initializer가 있는 멤버는 const여야 합니다.
const static int constStaticVar = 10; // const를 붙이면 클래스 내에서 초기화 가능
};
int MyClass::staticVar = 10; // 클래스 외부에서 초기화
int main()
{
// 객체를 통해 `static` 멤버 접근 가능
MyClass myClass;
cout << myClass.staticVar << '\n'; // 10
// 클래스 이름을 통해 `static` 멤버 접근 가능 (더 권장되는 방식)
cout << MyClass::staticVar << '\n'; // 10
return 0;
}
정적 멤버 함수
정적 멤버 함수는 모든 객체들이 '공유'하는 함수이다. this 포인터를 가지지 않기 때문에 비-정적 멤버 변수에는 접근할 수 없으며, 정적 멤버 변수 또는 다른 정적 함수에만 접근 가능하다.
#include <iostream>
using namespace std;
class MyClass {
private:
int instanceVar = 100; // 비-정적 멤버 변수
static int staticVar; // 정적 멤버 변수
public:
// 정적 함수
static void staticFunction() {
// cout << instanceVar; // ❌ 오류: 비-정적 멤버 변수 접근 불가
cout << staticVar << '\n'; // ✅ 가능: 정적 멤버 변수 접근
}
void nonStaticFunction() {
cout << instanceVar << '\n'; // ✅ 가능
cout << staticVar << '\n'; // ✅ 가능
}
};
// 정적 멤버 변수 정의
int MyClass::staticVar = 42;
int main() {
MyClass::staticFunction(); // ✅ 객체 없이 호출 가능
// MyClass::instanceVar; // ❌ 오류: 객체 없이 접근 불가능
MyClass obj;
obj.nonStaticFunction(); // ✅ 객체 생성 후 호출 가능
return 0;
}
참고 자료
'C++ > 문법 및 메소드(STL)' 카테고리의 다른 글
[C++] 탐구 일지 #5. 열거형(enum, enum class) (0) | 2025.02.19 |
---|---|
[C++] 탐구 일지 #4. struct와 class의 차이 (0) | 2025.02.19 |
[C++] 탐구 일지 #2. 타입의 별칭: typedef, using 키워드 (0) | 2024.12.21 |
[C++] 탐구 일지 #1. 소속을 구분하기 위한 네임스페이스(namespace) (0) | 2024.12.21 |
[문자열] 문자열을 정수로 stoi(), 숫자를 문자열로 to_string() (0) | 2024.03.21 |