상수 초기화
상수 초기화 (Constant initialization)
정적 변수의 초기 값을 컴파일 타임 상수로 설정하고 싶을 때가 있어요. 그런 초기화를 상수 초기화(constant initialization) 라고 해요. 상수 초기화는 다른 어떤 정적·스레드 지역 객체의 초기화보다 먼저 완료되는 게 보장돼요. 이 페이지에서 그 규칙을 살펴볼게요.
출처: cppreference
본문
상수 초기화는 다음 경우에 수행돼요.
- 정적 저장 기간을 가진 참조를 상수 표현식으로 초기화하는 경우.
- 정적 저장 기간을 가진 POD 타입 객체를 상수 표현식으로 초기화하는 경우. (until C++11)
- 정적 또는 스레드 저장 기간을 가진 참조를 초기화하는 경우. 단 다음 조건을 모두 만족해요.
- 초기화식에 나타나는 각 전체 표현식(암시적 변환 포함)이 상수 표현식이에요.
- 참조가 다음 중 하나에 묶여요.
- 정적 저장 기간 객체를 지시하는 lvalue
- 임시 객체
- 임시 객체의 하위 객체
- 함수
- 정적 또는 스레드 저장 기간을 가진 객체를 초기화하는 경우. 단 다음 조건 중 하나를 만족해요.
- 생성자 호출로 객체를 초기화하는데, 초기화 전체 표현식이 상수 표현식이고, 그 객체와 하위 객체(비-리터럴 클래스 타입이더라도)를 위한
constexpr생성자를 호출할 수도 있는 경우. - 그렇지 않으면 객체가 값 초기화(value-initialized)되거나 초기화식에 나타나는 모든 전체 표현식이 상수 표현식인 경우. (since C++11) (until C++17)
- 생성자 호출로 객체를 초기화하는데, 초기화 전체 표현식이 상수 표현식이고, 그 객체와 하위 객체(비-리터럴 클래스 타입이더라도)를 위한
- 정적 또는 스레드 저장 기간을 가진 변수나 임시 객체를, 그 전체 표현식이 상수 표현식인 초기화식으로 초기화하는 경우. 단 초기화되는 개체가 객체라면 그런 초기화식은 그 객체와 하위 객체(비-리터럴 클래스 타입이더라도)를 위한
constexpr생성자를 호출할 수도 있어요. (since C++17) (until C++20) - 정적 또는 스레드 저장 기간을 가진 변수나 임시 객체(until C++26)가 상수 초기화(constant-initialized)된 경우. (since C++20)
상수 초기화의 효과는 (해당) 대응 초기화의 효과와 같아요. 다만 정적 또는 스레드 지역(since C++11) 객체의 다른 어떤 초기화가 시작되기 전에 완전히 완료된다는 점이 보장돼요.
참고 (Notes)
컴파일러는 표준 순서의 초기화를 따랐을 때와 값이 같을 거라고 보장할 수 있다면, 다른 정적·스레드 지역(since C++11) 객체도 상수 초기화로 초기화하는 것이 허용돼요.
상수 초기화는 보통 프로그램이 메모리에 적재될 때, 프로그램의 런타임 환경을 초기화하는 일부로 일어나요.
예제 (Example)
#include <iostream>
#include <array>
struct S
{
static const int c;
};
const int d = 10 * S::c; // not a constant expression: S::c has no preceding
// initializer, this initialization happens after const
const int S::c = 5; // constant initialization, guaranteed to happen first
int main()
{
std::cout << "d = " << d << '\n';
std::array<int, S::c> a1; // OK: S::c is a constant expression
// std::array<int, d> a2; // error: d is not a constant expression
}
출력:
d = 50
결함 보고 (Defect reports)
다음 동작 변경 결함 보고는 이전에 발표된 C++ 표준에 소급 적용됐어요.
| DR | 적용 대상 | 발표된 동작 | 올바른 동작 |
|---|---|---|---|
| CWG 441 | C++98 | 참조가 상수 초기화될 수 없었음 | 상수 초기화 가능하게 됨 |
| CWG 1489 | C++11 | 객체를 값 초기화하는 것이 상수 초기화가 될 수 있는지 불명확했음 | 될 수 있음 |
| CWG 1747 | C++11 | 참조를 함수에 바인딩하는 것이 상수 초기화가 될 수 없었음 | 될 수 있음 |
| CWG 1834 | C++11 | 참조를 xvalue에 바인딩하는 것이 상수 초기화가 될 수 없었음 | 될 수 있음 |