Namespaces
Variants

Initialization

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

초기화 는 변수가 생성될 때 초기값을 제공합니다.

초깃값은 선언자 의 초기화 구역이나 new expression 에서 제공될 수 있습니다. 또한 함수 호출 과정에서도 발생합니다: 함수 매개변수와 함수 반환 값 또한 초기화됩니다.

목차

초기화자

각 선언자에 대해, 초기화자 (존재하는 경우)는 다음 중 하나일 수 있습니다:

= 표현식 (1)
= {}
= { 초기화자-목록 }
= { 지정-초기화자-목록 }
(2)

(since C++20)
( 표현식-목록 )
( 초기화자-목록 )
(3) (until C++11)
(since C++11)
{}
{ 초기화자-목록 }
{ 지정-초기화자-목록 }
(4) (since C++11)
(since C++11)
(since C++20)
1) 복사 초기화 구문.
2) Aggregate initialization syntax. (until C++11) List-initialization syntax. (since C++11)
3) 직접 초기화 구문.
4) 목록 초기화 구문.
expression - 모든 표현식(괄호로 묶이지 않은 comma expressions 제외)
expression-list - 쉼표로 구분된 표현식 목록(괄호로 묶이지 않은 comma expressions 제외)
initializer-list - 쉼표로 구분된 initializer clauses 목록(아래 참조)
designated-initializer-list - 쉼표로 구분된 designated initializer clauses 목록


초기화 절 은 다음 중 하나일 수 있습니다:

expression (1)
{} (2)
{ initializer-list } (3)
{ designated-initializer-list } (4) (C++20부터)

구문 (2-4) 은 통칭하여 brace-enclosed initializer list 라고 합니다.

초기화자 의미론

객체에 대한 초기화자가 지정되지 않으면, 해당 객체는 기본 초기화(default-initialized) 됩니다. 참조형(reference) 에 대한 초기화자가 지정되지 않으면, 프로그램은 형식에 맞지 않습니다(ill-formed).

객체에 지정된 초기화자가 ( ) (문법 제약으로 인해 선언자에서 나타날 수 없음)인 경우, 해당 객체는 value-initialized 됩니다. 참조에 지정된 초기화자가 ( ) 인 경우, 프로그램은 ill-formed입니다.

초기화자의 의미론(semantics)은 다음과 같습니다:

  • 초기화되는 엔티티가 참조인 경우, reference initialization 을 참조하십시오.
  • 그렇지 않으면, 초기화되는 엔티티는 객체입니다. 객체의 타입을 T 로 가정할 때:
  • 초기화자가 구문 (2) 인 경우:
(C++11까지)
(C++11부터)
#include <string>
std::string s1;           // 기본 초기화(default-initialization)
std::string s2();         // 초기화가 아님!
                          // 실제로는 매개변수가 없고 std::string을 반환하는 함수 "s2"를 선언함
std::string s3 = "hello"; // 복사 초기화(copy-initialization)
std::string s4("hello");  // 직접 초기화(direct-initialization)
std::string s5{'a'};      // 목록 초기화(list-initialization) (C++11부터)
char a[3] = {'a', 'b'}; // 집계 초기화(aggregate initialization)
                        // (C++11부터는 목록 초기화의 일부)
char& c = a[0];         // 참조 초기화(reference initialization)

비지역 변수

정적 저장 기간 을 가진 모든 비지역 변수는 main 함수 의 실행이 시작되기 전에 프로그램 시작 과정의 일부로 초기화됩니다(지연된 경우는 아래 참조). 스레드 지역 저장 기간을 가진 모든 비지역 변수는 스레드 함수 실행이 시작되기 전에 순서화된 상태로 스레드 시작 과정의 일부로 초기화됩니다. 이 두 종류의 변수 모두에 대해 초기화는 두 개의 별도 단계로 발생합니다:

정적 초기화

정적 초기화에는 두 가지 형태가 있습니다:

1) 가능한 경우, constant initialization 이 적용됩니다.
2) 그렇지 않은 경우, non-local static 및 thread-local 변수들은 zero-initialized 됩니다.

실제로:

  • 상수 초기화는 일반적으로 컴파일 타임에 적용됩니다. 미리 계산된 객체 표현은 프로그램 이미지의 일부로 저장됩니다. 컴파일러가 이를 수행하지 않더라도, 동적 초기화보다 먼저 초기화가 발생하도록 보장해야 합니다.
  • 영(0)으로 초기화될 변수들은 프로그램 이미지의 .bss 세그먼트에 배치되며, 이는 디스크 상에서 공간을 차지하지 않고 프로그램 로드 시 운영체제에 의해 0으로 채워집니다.

동적 초기화

모든 정적 초기화가 완료된 후, 비지역 변수의 동적 초기화는 다음과 같은 상황에서 발생합니다:

1) 비순서 동적 초기화(Unordered dynamic initialization) , 이는 (static/thread-local) 클래스 템플릿의 static 데이터 멤버 변수 템플릿(variable templates) (C++14부터) 명시적으로 특수화(explicitly specialized) 되지 않은 것들에만 적용됩니다. 이러한 static 변수의 초기화는 다른 모든 동적 초기화와 관련하여 비결정적으로 순서화됩니다(indeterminately sequenced) (변수가 초기화되기 전에 프로그램이 스레드를 시작하는 경우는 제외하며, 이 경우 해당 초기화는 순서화되지 않음(unsequenced)) (C++17부터) . 이러한 thread-local 변수의 초기화는 다른 모든 동적 초기화와 관련하여 순서화되지 않습니다(unsequenced).
2) 부분 순서 동적 초기화 , 이는 암시적 또는 명시적으로 인스턴스화된 특수화가 아닌 모든 인라인 변수에 적용됩니다. 부분 순서 V가 모든 번역 단위에서 순서 또는 부분 순서 W보다 먼저 정의된 경우, V의 초기화는 W의 초기화보다 순서가 지정됩니다(또는 프로그램이 스레드를 시작하는 경우 happens-before).
(C++17부터)
3) Ordered dynamic initialization , 단일 번역 단위 내에서 이러한 변수들의 초기화는 항상 해당 정의가 소스 코드에 나타나는 정확한 순서로 sequenced 됩니다. 서로 다른 번역 단위에 있는 정적 변수들의 초기화는 indeterminately sequenced됩니다. 서로 다른 번역 단위에 있는 스레드 지역 변수들의 초기화는 unsequenced됩니다.

정적 저장 기간 또는 스레드 저장 기간을 가진 비지역 변수의 초기화가 예외를 통해 종료되면, std::terminate 가 호출됩니다.

조기 동적 초기화

컴파일러는 다음 두 조건이 모두 충족되는 경우, 동적으로 초기화되는 변수를 정적 초기화의 일부로(본질적으로 컴파일 타임에) 초기화할 수 있습니다:

1) 동적 버전의 초기화는 초기화 이전에 네임스페이스 범위의 다른 객체 값들을 변경하지 않습니다
2) 정적 초기화 버전은 정적으로 초기화될 필요가 없는 모든 변수가 동적으로 초기화된다고 가정할 때, 동적 초기화에 의해 생성되는 값과 동일한 값을 초기화된 변수에 생성합니다.

위 규칙 때문에, 어떤 객체 o1 의 초기화가 네임스페이스 스코프 객체 o2 를 참조하는데, 이 o2 가 동적 초기화가 필요할 수 있지만 동일한 번역 단위에서 나중에 정의된 경우, 사용되는 o2 의 값이 완전히 초기화된 o2 의 값일지(컴파일러가 o2 의 초기화를 컴파일 시간으로 승격시킨 경우), 아니면 단순히 제로 초기화된 o2 의 값일지는 명시되지 않습니다.

inline double fd() { return 1.0; }
extern double d1;
double d2 = d1;   // 지정되지 않음:
                  // d1이 동적으로 초기화되면 동적으로 0.0으로 초기화되거나,
                  // d1이 정적으로 초기화되면 동적으로 1.0으로 초기화되거나,
                  // 정적으로 0.0으로 초기화됨 (두 변수가 모두 동적으로 초기화된 경우의 값이기 때문)
double d1 = fd(); // 정적으로 또는 동적으로 1.0으로 초기화될 수 있음

지연된 동적 초기화

정적 변수의 경우 동적 초기화가 main 함수의 첫 번째 문장 이전에 발생하는지, 스레드 지역 변수의 경우 스레드 초기 함수의 첫 번째 문장 이전에 발생하는지, 아니면 이후로 지연되는지는 구현에 따라 정의됩니다.

비인라인 변수의 초기화가 (비인라인 변수의 초기화가) (C++17부터) main/스레드 함수의 첫 번째 문장 이후로 지연되는 경우, 이는 초기화 대상 변수와 동일한 번역 단위에 정의된 정적/스레드 저장 기간을 가진 어떤 변수의 첫 번째 ODR-use 이전에 발생합니다. 주어진 번역 단위에서 어떤 변수나 함수도 ODR-used되지 않으면, 해당 번역 단위에 정의된 비지역 변수는 초기화되지 않을 수 있습니다(이는 온디맨드 동적 라이브러리의 동작을 모델링합니다). 그러나 번역 단위에서 어떤 것이든 ODR-used되는 한, 초기화 또는 소멸에 부수 효과가 있는 모든 비지역 변수는 프로그램에서 사용되지 않더라도 초기화됩니다.

인라인 변수의 초기화가 지연되는 경우, 해당 특정 변수의 첫 번째 ODR-use 이전에 발생합니다.

(since C++17)
// ============
// == 파일 1 ==
#include "a.h"
#include "b.h"
B b;
A::A() { b.Use(); }
// ============
// == 파일 2 ==
#include "a.h"
A a;
// ============
// == 파일 3 ==
#include "a.h"
#include "b.h"
extern A a;
extern B b;
int main()
{
    a.Use();
    b.Use();
}
// a가 main 진입 전에 초기화되면, A::A()에서 b를 사용하는 시점에 b가 아직 초기화되지 않았을 수 있음
// (동적 초기화는 번역 단위 간에 순서가 불확정적이기 때문)
// a가 main의 첫 번째 문장 이후에 초기화되는 경우 (File 1에 정의된 함수를 odr-use하여
// 해당 동적 초기화를 강제로 실행하는 경우), A::A에서 b를 사용하기 전에 b가 초기화됨

정적 지역 변수

지역(즉, 블록 범위) 정적 및 스레드 지역 변수의 초기화에 대해서는 static block variables 를 참조하십시오.

블록 범위에서 링크를 갖는 변수 선언에는 이니셜라이저를 사용할 수 없습니다. 외부 또는 내부 링크 . 이러한 선언은 반드시 extern 과 함께 나타나야 하며 정의가 될 수 없습니다.

클래스 멤버

비정적 데이터 멤버는 멤버 초기화 리스트 또는 기본 멤버 초기화 로 초기화할 수 있습니다.

참고 사항

비-지역 변수의 파괴 순서는 std::exit 에 설명되어 있습니다.

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
CWG 270 C++98 클래스 템플릿의 정적 데이터 멤버 초기화 순서가
명시되지 않았음
명시적 특수화 및 정의를 제외하고
순서 없음으로 명시됨
CWG 441 C++98 정적 저장 기간을 가진 비지역 참조가 항상
동적 초기화 전에 초기화되지 않았음
정적 초기화로 간주하여 항상
동적 초기화 전에 초기화됨
CWG 1415 C++98 블록 범위 extern 변수 선언이
정의일 수 있었음
금지됨 (해당 선언에서
초기화자는 허용되지 않음)
CWG 2599 C++98 초기화자에서 함수 인수를 평가하는 것이
초기화의 일부인지 불명확했음
초기화의 일부임

참고 항목

C 문서 참조: 초기화