Namespaces
Variants

Default-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

이는 객체가 초기화자 없이 생성될 때 수행되는 초기화입니다.

목차

구문

T 객체  ; (1)
new T (2)

설명

기본 초기화는 세 가지 상황에서 수행됩니다:

1) 자동, 정적 또는 스레드 지역 storage duration 을 가진 변수가 초기화자 없이 선언될 때;
2) 동적 저장 기간을 가진 객체가 초기화자가 없는 new-expression 으로 생성될 때;
3) 기본 클래스 또는 비정적 데이터 멤버가 constructor initializer list 에 언급되지 않고 해당 생성자가 호출될 때.

디폴트 초기화의 효과는 다음과 같습니다:

  • 만약 T 가 (cv 한정자가 있을 수 있는) non-POD (until C++11) 클래스 타입인 경우, 생성자들을 고려하여 빈 인수 목록에 대해 오버로드 해결 을 수행합니다. 선택된 생성자( 기본 생성자 중 하나)는 새 객체의 초기값을 제공하기 위해 호출됩니다;
  • 만약 T 가 배열 타입인 경우, 배열의 모든 요소가 기본 초기화됩니다;
  • 그 외의 경우에는 초기화가 수행되지 않습니다( 참고 참조).

const 객체의 기본 초기화

프로그램이 const -qualified type T 의 객체에 대한 default-initialization을 요구하는 경우, T는 const-default-constructible class type이거나 그 배열이어야 합니다.

클래스 타입 T T 의 기본 초기화가 사용자 제공 생성자를 호출하는 경우 T (기본 클래스에서 상속된 것이 아닌) (C++11부터) 또는 만약

초기화자가 없을 때 자동 저장 기간을 가진 (가능하다면 cv-qualified) 비-POD 클래스 타입(또는 이들의 배열)만이 기본 초기화되는 것으로 간주되었습니다. 동적 저장 기간을 가진 스칼라와 POD 타입은 초기화되지 않는 것으로 간주되었습니다 (C++11부터 이 상황은 기본 초기화의 한 형태로 재분류되었습니다).

(until C++11)
  • T 의 각 직접 비정적 데이터 멤버 M 이 클래스 타입 X (또는 그 배열)이고, X 가 const-default-constructible이며,
  • T 에 직접 variant members 가 없고,
(C++11 이전)
  • T 의 각 직접 비배리언트 비정적 데이터 멤버 M default member initializer 를 가지거나, M 이 클래스 타입 X (또는 그 배열)인 경우 X 가 const-default-constructible이고,
  • T 가 최소한 하나의 비정적 데이터 멤버를 가진 union인 경우, 정확히 하나의 variant member 가 default member initializer를 가지며,
  • T 가 union이 아닌 경우, 비정적 데이터 멤버를 최소한 하나 이상 가진 각 익명 union 멤버에 대해(있는 경우), 정확히 하나의 비정적 데이터 멤버가 default member initializer를 가지고,
(C++11 이후)

T 의 각 잠재적으로 생성되는 베이스 클래스는 const-default-constructible입니다.

미정의 값 및 오류 값

자동 또는 동적 저장 기간을 가진 객체에 대한 저장 공간이 확보될 때, 해당 객체는 indeterminate value 를 가집니다.

객체에 대해 초기화가 수행되지 않으면, 해당 객체는 값이 대체될 때까지 indeterminate value를 유지합니다.

(C++26 이전)

자동 또는 동적 저장 기간을 가진 객체에 대한 저장 공간이 확보될 때, 객체의 저장 공간을 구성하는 바이트들은 다음 초기값을 가집니다:

  • 객체가 동적 저장 기간을 가지거나, 첫 번째 선언이 [[ indeterminate ]] 로 표시된 변수 또는 function parameter 와 연관된 객체인 경우, 바이트들은 indeterminate values 를 가집니다.
  • 그렇지 않은 경우, 바이트들은 erroneous values 를 가지며, 각 값은 프로그램의 상태와 독립적으로 구현에 의해 결정됩니다.

객체(including subobjects )에 대해 초기화가 수행되지 않으면, 이러한 바이트는 값이 대체될 때까지 초기값을 유지합니다.

  • value representation 의 어떤 비트라도 indeterminate value를 가지면, 객체는 indeterminate value 를 가집니다.
  • 그렇지 않고 value representation의 어떤 비트라도 erroneous value를 가지면, 객체는 erroneous value 를 가집니다.
(C++26 이후)

평가가 불확정 값을 생성하는 경우, 그 동작은 undefined 입니다.

평가가 잘못된 값을 생성하는 경우, 그 동작은 잘못된 것입니다.

(since C++26)

특수 케이스

다음 유형들은 초기화되지 않은 상태를 허용하는(uninitialized-friendly) 유형입니다:

(C++17부터)
  • unsigned char
  • char , 기본 타입이 unsigned char 인 경우

부정확하거나 오류가 있는 (C++26부터) value 이 주어졌을 때, value 초기화되지 않은 결과 값 은 다음과 같습니다:

  • 부정 값(indeterminate value), 만약 value 또한 부정 값인 경우.
  • value , 만약 value 가 오류 값을 나타내는 경우.
(C++26부터)

평가가 eval 가 초기화 친화적 타입의 불확정 또는 오류 (C++26부터) value 을 생성하는 경우, 다음 상황에서의 동작은 명확히 정의됩니다:

  • eval 는 다음 표현식과 피연산자 중 하나의 평가입니다:
이 경우 연산의 결과는 value 의 초기화되지 않은 결과 값입니다.
  • eval 는 왼쪽 피연산자가 초기화-친화적(uninitialized-friendly) 타입의 lvalue인 단순 할당 연산자 의 오른쪽 피연산자 평가입니다.
이 경우, 왼쪽 피연산자가 참조하는 객체의 값은 value 의 초기화되지 않은 결과 값으로 대체됩니다.
  • eval 는 초기화되지 않은 상태를 허용하는 타입의 객체를 초기화할 때 초기화 표현식의 평가입니다.
  • value 는 초기화되는 객체의 타입이 std::byte 가 아닌 경우 std::byte 타입일 수 없습니다.
(C++17부터)
이 경우, 해당 객체는 value 의 초기화되지 않은 결과 값으로 초기화됩니다.

초기화에 친화적인 타입의 미정의 값을 변환하면 미정의 값이 생성됩니다.

초기화 친화적 타입의 오류 값을 변환하면 오류 값이 생성되며, 변환 결과는 변환된 피연산자의 값입니다.

(since C++26)
// Case 1: 동적 저장 기간을 가진 초기화되지 않은 객체들
// 모든 C++ 버전: 불확정 값 + 정의되지 않은 동작
int f(bool b)
{
    unsigned char* c = new unsigned char;
    unsigned char d = *c; // OK, "d"는 불확정 값을 가짐
    int e = d;            // 정의되지 않은 동작
    return b ? d : 0;     // "b"가 true일 경우 정의되지 않은 동작
}
// Case 2: 자동 저장 기간을 가진 초기화되지 않은 객체들
// C++26 이전: 불확정 값 + 정의되지 않은 동작
// C++26 이후: 오류 값 + 오류 동작
int g(bool b)
{
    unsigned char c;     // "c"는 불확정/오류 값을 가짐
    unsigned char d = c; // 정의되지 않은/오류 동작 없음,
                         // 하지만 "d"는 불확정/오류 값을 가짐
    assert(c == d);      // 성립하지만, 두 정수 승격 모두
                         // 정의되지 않은/오류 동작을 가짐
    int e = d;           // 정의되지 않은/오류 동작
    return b ? d : 0;    // "b"가 true일 경우 정의되지 않은/오류 동작
}
// Case 2와 동일
void h()
{
    int d1, d2;  // "d1"과 "d2"는 불확정/오류 값을 가짐
    int e1 = d1; // 정의되지 않은/오류 동작
    int e2 = d1; // 정의되지 않은/오류 동작
    assert(e1 == e2); // 성립
    assert(e1 == d1); // 성립, 정의되지 않은/오류 동작
    assert(e2 == d1); // 성립, 정의되지 않은/오류 동작
    // 정의되지 않은/오류 동작 없음,
    // 하지만 "d2"는 불확정/오류 값을 가짐
    std::memcpy(&d2, &d1, sizeof(int));
    assert(e1 == d2); // 성립, 정의되지 않은/오류 동작
    assert(e2 == d2); // 성립, 정의되지 않은/오류 동작
}

참고 사항

참조와 const 스칼라 객체는 기본 초기화될 수 없습니다.

기능 테스트 매크로 표준 기능
__cpp_constexpr 201907L (C++20) 사소한 기본 초기화 및 asm-선언 in constexpr functions

예제

#include <string>
struct T1 { int mem; };
struct T2
{
    int mem;
    T2() {} // "mem"이 초기화 목록에 없음
};
int n; // 정적 비클래스, 2단계 초기화 수행:
       // 1) 0 초기화가 n을 0으로 초기화
       // 2) 기본 초기화는 아무 작업도 하지 않아 n이 0으로 유지됨
int main()
{
    [[maybe_unused]]
    int n;            // 비클래스, 값은 불확정
    std::string s;    // 클래스, 기본 생성자 호출, 값은 ""
    std::string a[2]; // 배열, 요소들을 기본 초기화, 값은 {"", ""}
//  int& r;           // 오류: 참조
//  const int n;      // 오류: const 비클래스
//  const T1 t1;      // 오류: 암시적 기본 생성자를 가진 const 클래스
    [[maybe_unused]]
    T1 t1;            // 클래스, 암시적 기본 생성자 호출
    const T2 t2;      // const 클래스, 사용자 제공 기본 생성자 호출
                      // t2.mem은 기본 초기화됨
}

결함 보고서

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

DR 적용 대상 게시된 동작 올바른 동작
CWG 178 C++98 값 초기화가 없었음;
빈 초기화자는 기본 초기화를 수행함
(단, new T ( ) 는 0 초기화도 수행함)
빈 초기화자는
값 초기화를 수행함
CWG 253 C++98 const 객체의 기본 초기화가
암시적으로 선언된 기본 생성자를 호출할 수 없었음
모든 하위 객체가 초기화된 경우 허용됨
CWG 616 C++98 초기화되지 않은 모든 객체의
lvalue에서 rvalue로의 변환이 항상 UB였음
indeterminate unsigned char 는 허용됨
CWG 1787 C++98 indeterminate unsigned char
를 레지스터에 캐시하여 읽는 것이 UB였음
well-defined로 변경됨

참고 항목