Static의 의미
1. class 밖에 선언된 static: means linkage to the symbol would be static. translation unit에서만 visible할 것
2. class 안: 그 변수가 모든 그 class의 instance 들에 의해 공유될 것
1. class밖에 선언된 static
static int s_Var (s_는 conventionally 사용되는 static var 표시)
컴파일러는 이 translation unit에서만 static 요소의 정의를 찾으려 할 것이다.
예를 들어서 두 개의 소스파일에 각각 s_Var이라는 변수를 static하게 선언하면 문제없이 컴파일된다.
하지만 한 소스파일 (혹은 두 소스파일 모두) s_Var 변수에 static선언을 빼게 되면 컴파일 에러가 발생한다.
왜냐하면, 같은 변수가 두 번 선언되었기 때문이다.
전자의 경우에는, 각 translation unit 고유의 s_Var이었기 떄문에 충돌이 없었지만, static을 빼버리며 그 변수는 모든 translation unit에 선언된 변수라 중복이 발생하는 것이다.
// Main.cpp
int s_Var = 10;
// Static.cpp
int s_Var = 5;
외부에서 해당 변수의 정의를 찾는 다는 의미로 extern 선언을 해줄 수 있다.
// Main.cpp
extern int s_Var;
// Static.cpp에서 해당 변수를 찾을 것.
// Static.cpp
int s_Var = 5;
이외에도, static은 함수에도 선언할 수 있다.
global할 필요가 없는 것은 static으로 선언하는 것이 안전하다. 마치 private을 굳이 사용하는 것처럼.
static 선언을 하지 않으면 모든 translation unit을 검색해서 찾아내려 하니까..
2. class/struct 안에 static
보통 객체지향 언어들 모두 class안에 static을 선언하는 문법을 갖고 있다.
class안에 static 변수를 선언한다는 건 그 class로 만든 모든 인스턴스들이 그 변수 하나를 공유한다는 것이다.
static함수는 인스턴스 없이 사용할 수 있게 되며, 대신 그 class로 만들어진 인스턴스들의 변수들을 이용할 수 없다.
struct Entity{
static int x, y;
void print(){
cout << x << ", " << y << endl;
}
}
// 아래의 선언들이 필요함 - 아니면 unresolved external symbol 오류가 난다.
// 왜냐면 위 static 변수들을 어딘가에 정의할 필요가 있기 때문에, 그래야 링커가 연결 가능
int Entity::x;
int Entity::y;
int main(){
Entity e;
e.x = 2;
e.y = 3;
Entity e1 = { 5, 8 }; // 에러 뜸, x, y는 인스턴스의 변수가 아니기 떄문
Entity e1;
e1.x = 4;
e1.y = 8;
e.print();
e1.print();
// 둘다 결과는 4, 8 >> 왜냐면 x, y는 하나니까
// 결국 접근은 인스턴스를 통해서 할 필요가 없다.
Entity::x = 5;
Entity::y = 6;
}
static 함수를 살펴보자면,
struct Entity{
static int x, y;
static void print(){
cout << x << ", " << y << endl;
}
}
int Entity::x;
int Entity::y;
int main(){
Entity e;
Entity::x = 4;
Entity::y = 8;
Entity::print();
// 바로 print() 함수를 부를 수 있다.
// 대신 이게 가능한 건, x, y가 모두 역시 static하기 때문에
}
주의할 점은 static method가 static변수에만 접근할 수 있다는 것이다.
만약 static 메소드에서 인스턴스를 사용하고 싶으면 해당 인스턴스를 변수로 넘길 수 있도록 선언해줘야 한다.
struct Entity{
int x, y;
static void print(){
cout << x << ", " << y << endl;
}
}
static void print(Entity e){
std::cout << e.x << ", ", e.y << std::endl;
}
int main(){
Entity e;
e.x = 2;
e.y = 3;
Entity::print(e); // parameter로 인스턴스를 넘김
}
3. Local Static
life time of entire program but its scope is limited to that function or if statement or whatever
- life time: how long this variable will last in memory
- scope: where can we actually access the variable
#include <iostream>
using namespace std;
int j;
void Func(){
int i = 0;
i++;
cout << i << endl;
}
void FuncJ(){
j++;
cout << j << endl;
}
void FuncK(){
static int k = 0;
k++;
cout << k << endl;
}
int main(){
Func();
Func();
Func();
Func();
Func();
// 결과는 1 1 1 1 1, 왜냐면 함수를 부를 때마다 i가 새로 선언되었기 때문
FuncJ();
FuncJ();
FuncJ();
FuncJ();
FuncJ();
// 결과는 1 2 3 4 5
// 대신 이렇게 하면 j에 어디서나 접근할 수 있어서 안전하지 않아짐
FuncK();
FuncK();
FuncK();
FuncK();
FuncK();
// 결과는 1 2 3 4 5 이면서 함수 외부에서 접근할 수 없다.
}
class에서 적용시켜보자.
만약 내가 어떤 클래스를 선언할 때 이 클래스의 인스턴스가 딱 하나였으면 좋겠다면, 아래와 같이 선언하면 된다
class Singleton{
private:
static Singleton* s_Instance;
public:
static Singleton& Get() { return s_Instance; }
void print(){};
}
};
Singleton* Singleton::s_Instance = nullptr;
int main(void){
Singleton::Get().print();
}
혹은 아래와 같이, 함수 내에서 인스턴스를 선언하고 인스턴스를 반환한다.
class Singleton{
public:
static Singleton& Get() {
static Singleton s_Instance;
// 만약 여기서 static을 빼버리면 공간이 스택에 생겨서, 이 함수가 끝남과 동시에
// 저장공간이 없어질 것이다. 참조값으로 반환하고 있기에 문제가 생긴다.
return s_Instance; }
void print(){};
}
};
Singleton* Singleton::s_Instance = nullptr;
int main(void){
Singleton::Get().print();
}
Singleton 객체가 static으로 선언되었기 떄문에, Get()을 처음으로 호출하는 때에 메모리가 할당되고, 그 이후부턴 이미 있는 메모리 공간의 참조값을 반환하는 형식으로 실행된다.
'언어 > C&C++ 기본' 카테고리의 다른 글
[C] Storage Class (extern, static 등) (0) | 2021.08.09 |
---|---|
[C++] ENUMS, Constructor, Destructor (0) | 2021.07.02 |
[C++] Class (0) | 2021.06.25 |
[C++] Header Files (0) | 2021.06.14 |
[C++] Variables, Functions, Pointers, References (0) | 2021.06.14 |