static에 대한 공부
static
정적. 무언가를 데이터 영역에 할당해서 라이프타임을 프로그램의 시작과 끝으로 하기 위해 붙이는 키워드
반대되는 개념으론 dynamic한 무언가. 예 : 정적배열<-> 동적배열
그런데 어디서 선언되냐에 따라서, 즉 선언된 스코프에 따라서 의미가 조금 다르다.
1. 일반 함수 내의 지역변수로 선언될 경우
함수내의 static 변수의 선언이 "실행"될 때 처음 초기화 된다.
고유하기에 함수들이 공유하지만, 접근범위는 해당 스코프로 제한된다.
1 2 3 4 5 6 7 8 9 | void X1() { static int a = 10; if (a) static int b = 20; else static int c = 30; } | cs |
X1()이 호출되어 3행을 실행하며 a가 초기화되고, 분기문을 통해 b가 초기화 된다. c는 초기화되지 않는다.
2. 전역 변수로 선언될 경우
해당 traslation unit (.cpp + #include한 .h)로 link범위가 한정된다.
일반적인 전역변수가 external linkage를 갖는다면 static 전역변수는 internal linkage다.
1 2 3 4 5 6 7 8 9 10 11 | //somewhere.cpp int a = 40; static int b = 50; int c() { return 60; }; static int d(){ return 70; }; | cs |
어딘가의 cpp에 위와같이 정의되있다고 할 때
1 2 3 4 5 6 7 8 9 10 11 12 13 | extern int a; extern int b; extern int c(); extern int d(); int main() { cout << a << endl; //ok cout << b << endl; //link error! cout << c() << endl; //ok cout << d() << endl; //link error! } | cs. |
a는 external 하기에 extern 키워드로 갖다 쓸 수 있는 반면
b는 internal해서 갖다 쓸수가 없다. 함수도 마찬가지다.
c++에서는 namespace로 해결되는 일이라, 더이상 사용할 일이 없는 C의 잔재인듯 하다. (stroustrup 교수님도 책에서 external 쓰지 말라고 하셨다)
3. 클래스의 멤버 변수로 선언될 경우
1 2 3 4 5 | class Cstatic { public: static int a; }; | cs |
1 2 3 | #include "Cstatic.h" int Cstatic:: a = 50; | cs |
이런 방식으로 선언과 정의를 분리해서 해야하며, 정의는 클래스와 같은 스코프에 있어야 한다.
이왕이면 cpp에 정의를 두는 게 헤더를 어딘가에서 #include 할 때 중복정의되는 문제를 피할 수 있다. (아니면 #ifndef)
다음과 같은 초기화는 에러다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #pragma once class Cstatic { public: Cstatic(int aa) : a(aa) //error { a = aa; // 초기화가 아닌 대입이다. } ~Cstatic(); static int a{ 50 }; //error }; | cs |
그 이유는 Cstatic 타입의 객체를 만들 때마다 static int a를 50으로 초기화해서 생성한다는 건 뭔가 이상하지 않은가?
클래스 내의 static 변수는 객체의 인스턴스유무에 상관없이 (단 접근 지정자에 따라) 네임스페이스를 통해 접근할 수 있는 전역변수의 느낌이다.
같은 클래스의 인스턴스끼리는 공유해서 사용한다.
public일 경우 다음과 같이 접근해볼 수 있다.
1 2 3 4 5 6 | int main() { cout << Cstatic::a << endl; ++Cstatic::a; cout << Cstatic::a << endl; } | cs |
마찬가지로 static 멤버 함수도 네임스페이스를 통해 접근할 수 있는 함수의 느낌이다.
단 클래스의 인스턴스가 없을 때에도 static 함수는 메모리에 올라가 있으므로, static 함수에서 non-static 변수의 사용은 불가하다.
즉 static 멤버함수에선 static 멤버변수만 사용 가능하다. 마찬가지로 같은 클래스의 모든 인스턴스들에서 공유해서 사용한다.
1 2 3 4 5 6 7 8 9 10 11 12 | class Cstatic { public: static int a; int b; static void test() { ++a; ++b; //error } }; | cs |
4. 뭔가의 앞에 선언
그냥 보게되서 올림.
1 2 3 4 5 6 7 | static class Ctest { public: int a; } tt; static Ctest tt; //둘은 같다. | cs |
'프로그래밍 > C, C++ 공부' 카테고리의 다른 글
이터레이터의 무효화 규칙 (0) | 2018.03.27 |
---|---|
오늘 주의깊게 본 스택오버플로우 (0) | 2018.03.22 |
기본 생성자, 복사 생성자, 복사 대입자 그리고 암시적 형변환과 explicit (0) | 2018.03.17 |
복사 생성자에서는 왜 파라메터의 private 멤버에 접근할 수 있을까 (0) | 2018.03.16 |
C++ 11 (0) | 2018.03.11 |