'Static member initialization'에 해당되는 글 1건

  1. 2009.04.07 [C++] Static member initialization

[C++] Static member initialization

CS/C/C++ 2009. 4. 7. 11:24
Q.
// Widget.cpp
int Widget::state_;
위와 같은 코드를 보시고 class의 static member 변수의 초기화를 안했다고 생각하고 있진 않으신가요?.
표준 C++에서 정의하고 있는 static member 변수 초기화에 대해 간단히 정리했습니다.



A.
먼저 표준 C++에서 정의하고 있는 세가지 storage duration에 대해 간단히 정리해보겠습니다.

static storage duration - dynamic storage duration을 가지지 않으면서 local인 객체들은 모두 static storage duration을 가지게 됩니다. 이 storage에 있는 객체들은 속해 있는 프로그램의 duration만큼 지속됩니다. 또한 local 변수의 선언에 static keyword를 사용하게 되면 역시 static storage duration을 가지게 됩니다. class의 data member에 사용된 static keyword도 마찬가지입니다.
 
automatic storage duration - auto, register를 명시적으로 선언한 local 객체, 혹은 static, extern등이 명시적으로 선언되지 않은 local 객체들은 automatic storage duration을 가지게 됩니다. 이 storage에 있는 객체들은 자신이 생성된 블록이 끝나기 전까지만 지속됩니다.
 
dynamic storage duration - 프로그램 수행 중에 new-expressions을 가지고 생성된 객체들은 dynamic storage duration을 가지게 되며 delete-expressions를 사용하여 파괴될 수 있습니다.
 
위와 같은 용어의 이해를 바탕으로 ISO/IEC-14882의 3.6.2(1)을 참고하면 다음과 같습니다.

Static storage duration을 가지는 객체들을 위한 storage는 어떤 다른 초기화보다 먼저 0으로 초기화된다(zero-initialization).
이러한 초기화와 상수 초기화를 합쳐서 정적(static) 초기화라고 부르고 나머지는 동적(dynamic) 초기화라고 부른다.
 
static storage duration을 가지는 POD(Plain Old Data) 객체들의 상수 초기화는 항상 어떤 다른 dynamic 초기화보다 먼저 일어나게 된다.
 
동적 초기화되는 객체들과, 같은 translation unit안의 namespace scope에 정의된 static storage duration을 갖는 객체들은 transation unit안에 선언된 순서에 따라 초기화된다.
 
// Widget.cpp
int Widget::state_;
이제 state_ 변수는 static storage duration을 가지게 되고 따라서 다른 종류의 초기화에 앞서 0으로 초기화된다는 사실을 알 수 있습니다.

따라서 위의 코드는 초기화를 잊은 코드가 아니라는 사실을 알 수 있습니다.
단지 코드의 작성자는 그 state_ 변수를 0으로 초기화하려고 했었던 것이죠.

참고로 local에 선언된 static 변수는 어떤 다른 초기화 과정에 앞서 0으로 초기화됩니다.
만약 그 변수가 constant-expressions를 가진 POD 타입일 경우 선언되어 있는 블록이 시작되기 전에 초기화되며 이외의 경우 선언된 라인이 처음 실행되는 순간에 초기화됩니다. 이때 객체의 생성자가 exception을 throw하게 되면 다음 실행되는 순간에 다시 초기화를 시도하게 됩니다.

만약 이 객체가 생성되는 순간에 다시 함수에 재진입(re-enter)하게 되면 (recursively) 결과는 정의되어 있지 않습니다(undefined). 아래의 코드를 참고하세요.

int foo(int i) {
static int s = foo(2 * i); // recursive call. undefined
return i + 1;
}
 
Static storage duration을 가지는 변수들이 하나의 translation unit 안에 정의되어 있다면 선언되어 있는 순서대로 초기화된다는 것을 보장받지만 다른 translation unit 안에 정의되어 있는 static storage duration을 가지는 변수들간의 초기화 순서는 정의되어 있지 않습니다. 따라서 이러한 다른 translation unit의 변수들간의 dependency는 가능하면 피해야 합니다.

하지만 어떠한 경우라도 변수들의 파괴는 정확히 초기화 순서의 반대로 일어납니다.

이 글은 ISO/IEC 14882 문서를 참고하여 만들어졌습니다.

이 페이지의 내용보다 더 자세한 객체의 생성, 삭제에 관련된 다양한 사항들은 위의 문서를 참고하시면 됩니다.




정적 클래스 멤버는 객체의 일부가 아니라 따로 저장된다. 
정적 클래스 멤버에 대해서는 정적 멤버를 클래스 선언 밖에서 별도의 명령문으로 따로 초기화 한다.
하지만, 정적 멤버가 정수형 또는 열거형의 상수이면 클래스 선언 자체에서 초기화할 수 있다.
: