c++에서 static 한정자가 하는 일

C++을 처음 배울 때 사람들이 많이 헷갈리는 것 중 하나가 static이다. 사실 이건 배우는 사람의 문제도 아니고 가르치는 방법의 문제도 아니다. 그저 C++에서 static을 다양한 용도로 사용하고 있기 때문이다.

static storage

static 키워드를 사용하는 한 가지 목적은 지역 변수에 할당할 객체를 static storage로 만들기 위해서다. C++에서 block scope에 선언되는 변수가 가지는 객체는 기본적으로 automatic storage에 선언되어 block이 끝나면 자동으로 소멸한다. 하지만 간혹 특정한 범위 내에서만 접근할 수 있으면서 프로그램이 끝날 때까지 살아있는 객체, 다시 말해 지칭하는 변수는 block scope에 선언됐지만, static storage duration을 가지는 객체가 필요할 때가 있다. 이럴 때 static 한정자를 사용하면 된다. block scope에 선언되는 지역 변수에 static 한정자를 붙이면 이 변수가 가리키는 객체는 static storage duration을 가지고, block이 종료돼도 소멸하지 않는다.

internal linkage

static 한정자는 namespace scope에 선언되는 변수에도 사용될 수 있다. 하지만 namespace scope에 선언된 변수가 가지는 객체는 기본적으로 static storage에 할당된다. 따라서 namespace scope에 선언된 변수에 붙은 static 한정자는 객체가 할당될 storage에 영향을 주지 않는다. 여기서 static은 다른 의미를 가진다.

static 한정자는 namespace scope에서는 변수뿐 아니라 함수 선언에도 붙일 수 있다. 이 경우 선언된 변수나 함수의 linkage를 internal linkage로 바꿔서 translation unit 밖으로 나가지 않도록 해준다.

static member

C++에서 static이 가지는 마지막 의미는 클래스의 멤버 변수나 함수를 전역 멤버 변수와 전역 함수로 만드는 것이다. 클래스의 전역 멤버 변수는 프로그램이 종료될 때까지 살아있는 객체로, static storage에 할당된다. 전역 멤버 변수는 클래스와 독립적인 생명 주기를 가지기 때문에 전역 멤버 변수가 될 타입은 선언하는 시점에서 complete type일 필요가 없다. 전방 선언된 타입을 이용해 선언하더라도 정의하는 시점에서 complete type을 알기만 하면 된다.

전역 멤버 함수는 클래스와는 관련 있지만, 객체와 연관되지 않는 함수를 말한다. 즉, 자기 자신(this)을 포인터로 넘겨받지 않으며, virtual function이 되거나 함수의 선언에 const를 붙일 수도 없다. 또한, 전역 멤버 변수나 전역 멤버 함수는 그 클래스와 같은 linkage를 가진다. 즉, block scope에 선언된 클래스의 전역 함수나 전역 변수는 linkage를 가지지 않고, unnamed namespace 안에 선언된 클래스의 전역 함수나 전역 변수는 internal linkage를 가진다.

static storage, internal linkage, static member 이 세 가지가 C++에서 static 키워드가 가지는 의미이다. 사실 이 3가지는 완전히 독립된 개념인데 같은 키워드를 사용하였기에 사람들을 헷갈리게 한다. C++ 뿐 아니라 다른 언어에서도 이런 경우가 종종 있다. 왜냐하면, 새 키워드를 추가하면 추가된 키워드를 다른 이름으로 사용하던 기존의 코드가 돌아가지 못하게 되고, 이는 하위 호환성을 잃는 결과를 가져오기 때문에 보통 언어에서 새 키워드를 추가하는 것을 싫어하기 때문이다.

사실 C++에는 이미 unnamed namespace를 사용해서 이름을 internal linkage로 만드는 방법이 있다. 그래서 C++11이 제정될 때 namespace scope에 선언된 이름을 internal linkage로 만들기 위해서 static 한정자를 사용하는 것을 deprecate 시키자는 의견도 있었으나 하위 호환성을 깨지 않는 방향으로 가기 위해 받아들여지지 않았다. 결국, 이 3가지 기능이 전부 남게 되었고, 앞으로도 한동안은 이 중 어느 한 기능도 없어지지 않을 것으로 보인다.

댓글

이 블로그의 인기 게시물

[C++] enum class - 안전하고 쓰기 쉬운 enum

Log Aggregator 비교 - Scribe, Flume, Fluentd, logstash

RAII는 무엇인가

[Python] cache 데코레이터로 최적화하기

[Web] SpeechSynthesis - TTS API