본문 바로가기

# Lang/C++

6.2 중괄호 리스트 초기화

 중괄호 초기화,  소괄호 초기화

관점에 따라 초기화 정책이 바뀐다 :

  • 어떤 괄호를 사용했는가?  (소괄호, 중괄호)
  • 괄호 안에 인자의 수는 몇개인가? (0개, 1개,  2개 이상)


사례 구분 :

  • 인자없는 소괄호 : value initializaiton

  • 인자없는 중괄호 : value initialization

  • 단일인자 소괄호 : direct initialization

  • 단일인자 중괄호 : direct initialization

  • 다중인자 소괄호 : direct initialization

  • 다중인자 중괄호 : aggregate initialization


서론 :

여러개의 인자를 다룰 때에는,

소괄호 초기화와 중괄호 초기화의 차이점을 알아야 한다. 


 집합 초기화 (Aggregate initialization)

다중인자를 다루는 중괄호 초기화 방식.


여러개의 인자를 하나의 집합으로 취급하여 이니셜라이저에 넘기며,

이니셜라이저는 집합에서 값을 하나씩 꺼내며 순차적으로 초기화한다.

각 요소의 자료형이 달라도 사용할 수 있다.


표준에 정의된 모든 기능을 완벽하게 지원하는 컴파일러는 아직 없다.

자신의 컴파일러가 어디까지 지원하는지 테스트가 필요.


다양한 이름 :

  • 집합 초기화 (Aggregate initialization)

  • 중괄호 리스트 초기화 (Braced-list initialization)

  • 감싸진 중괄호 이니셜라이져 리스트 (Brace-Enclosed initialization list)


발생 사례 :

  • T object = { arg1, arg2, ... }

  • T object { arg1, arg2, ... }   // since C++11


 Since C++20

C++20 부터 이름있는 다중인자 소괄호도 집합 초기화로 취급된다고 한다.

이름없는 다중인자 소괄호는 여전히 direct 초기화로 유지된다.

  • T object ( arg1, arg2, ... )  // Aggregate initialization,  since C++20

  • T( arg1, arg2, ...)  // Direct initialization.


지금은 소괄호와 중괄호를 주의하여 사용해야 하지만,

추후에는 이름유무가 중요한 주의점이 될 것 같다.


 기본적인 타입 제약

다음 타입에만 중괄호 리스트 초기화를 적용할 수 있다.

중괄호 리스트 초기화는 다중인자에 관련이 있음을 생각해보자.

  • 어레이 (Array)

  • 클래스 (Class)

  • 구조체 (Struct)

  • 공용체 (Union)


어레이는 각 요소를 묶어서 다중인자로 생각할 수 있으며,

클래스는 각 멤버를 묶어서 다중인자로 생각할 수 있다.

구조체와 공용체는 클래스와 같다.


 구체적인 타입 제약

클래스는 좀 더 제약사항이 많으며,

매 버전마다 제약이 변경되고 있다.


pre C++ 11 :

  • 자신 클래스에 virtual, private, protected가 없을 것.

  • 부모 클래스가 없을 것.

  • user-declared 생성자가 없을 것.  // 클래스 안에서 선언된 생성자.

  • user-provided 생성자가 없을 것.  // 클래스 밖에서 수여된 생성자.


C++ 11 :

  • 자신 클래스에 virtual, private, protected가 없을 것.

  • 부모 클래스가 없을 것.

  • user-declared 생성자가 없을 것.

  • user-provided 생성자가 없을 것.

  • user-provided 생성자가 없을 것. (defaulted, deleted는 허용)

  • 기본 멤버 초기화를 하지 않을 것.

class data {
public:
        int a = 3;   // default member initialization.
}

C++ 14 :
  • 자신 클래스에 virtual, private, protected가 없을 것.
  • 부모 클래스가 없을 것.

  • user-provided 생성자가 없을 것. (defaulted, deleted는 허용).

  • 기본 멤버 초기화를 하지 않을 것. 


C++ 17 :

  • 자신 클래스에 virtual, private, protected가 없을 것.
  • public만 초기화 함.
  • 부모 클래스가 없을 것.

  • 부모 클래스를 virtual, private, protected로 상속받지 않을 것.

  • user-provided 생성자가 없을 것. (defaulted, deleted는 허용).

  • user-provided, inherited, explicit 생성자가 없을 것.  (defaulted, deleted는 허용.)



C++ 20 :
  • public만 초기화 함.
  • 부모 클래스를 virtual, private, protected로 상속받지 않을 것.
  • user-provided, inherited, explicit 생성자가 없을 것.  (defaulted, deleted는 허용.)

  • user-declared, inherited 생성자가 없을 것.



 중괄호 리스트 초기화의 특징 (효과)

  • 반복하여 내부 초기화를 진행
    생성자가 없어도 초기화를 진행할 수 있는 이유.
    순차적으로 copy initialization을 발생시킨다.  (per copy-initialization)
    임의로 중간의 요소를 건너 뛸 수 없음.
    만약, 시그니쳐가 일치하는 생성자가 있다면 해당 생성자를 호출한다.


  • 재귀적으로 초기화 가능
    중괄호 리스트 초기화의 인자가 다시 중괄호 리스트로 주어졌다면,
    해당 요소에 대해 다시 중괄호 리스트 초기화를 진행한다.

  • 정적, 이름없는 비트필드는 무시
    static 멤버나, 이름없는 비트필드는 중괄호 리스트 초기화에서 무시된다.

  • 요소를 덜 준 초기화
    배열이나 클래스에 충분한 요소를 공급하지 못했을 때 발생.
    적어도 중괄호 리스트에 주어진 요소의 수 만큼 순차적으로 초기화한다.

    초기화되지 못한 값은 value-initialization으로 진행하지만,
    초기화 되지 못한 값에 참조형식이 있다면 컴파일 에러를 발생시킨다.


  • 요소를 더 준 초기화
    클래스나 사이즈가 명확한 배열에 요소를 과공급했을 때 발생.
    컴파일 에러를 발생시킨다.

  • 크기를 알 수 없는 배열의 초기화
    배열의 최대 인덱스를 알 수 없어도, 리스트에 주어진 만큼은 초기화한다.
    이 때, 리스트에 주어진 요소의 크기는 컴파일러가 반드시 알 수 있어야 한다.


 상속 클래스에서의 중괄호 리스트 초기화

중괄호 리스트 초기화는 재귀적인 진행이 가능하다는 것을 이용한다.

부모 클래스의 중괄호 리스트를 차례대로 적어낸다.

class Core {
public:
    int core;
};

class Data : public Core {
public:
    int a;
    int b;
};

Data a = { {10}, 20, 30 };


 적용 예제 (1) 클래스

class Person {
public:
    string name;
    int age;
};
Person a{"AeroCode", 25};


 적용 예제 (2) std::pair

std::pair<int, std::string> p = {1, "Hello, world!"};


 Designated initializers

Designator를 혼용하여 중괄호 리스트 초기화를 진행.

중간의 요소의 건너뛸 수 있도록 도와줌.

단, 뒷 요소의 Designator를 사용하면, 앞 요소의 Designator가 금지됨.

class data {
public:
        string name;
        int v1;
        int v2;
        int v3;
        int v4;
        int v5;
};

data a{"X",  1,  .v4=4,  5};   //  = {"X", 1, 0, 0, 4, 5}
data b{"Y", .v4=4, .v3=3};  // Compile Error. 지나간 요소의 designator는 사용할 수 없음.


 참고 문헌

 

aggregate initialization - cppreference.com

Initializes an aggregate from braced-init-list [edit] Syntax T object = {arg1, arg2, ...}; (1) T object {arg1, arg2, ...}; (2) (since C++11) T object = { .designator = arg1 , .designator { arg2 } ... }; (3) (since C++20) T object { .designator = arg1 , .de

en.cppreference.com

 

Initialization in C++ is Seriously Bonkers

I was recently reminded of why I think it’s a bad idea to teach beginners C++. It’s a bad idea because it is an objective mess—albeit a beautiful, twisted, tragic, wondrous mess. Despite the current state of the community, this post is not a polemic agains

mikelui.io

 

'# Lang > C++' 카테고리의 다른 글

6.4 균일된 초기화 방식  (0) 2019.05.07
6.3 이니셜라이져 리스트  (0) 2019.05.04
6.1 로컬변수 초기화  (0) 2019.04.22
5.2 완벽한 전달  (0) 2019.04.19
5.1 이동 의미론  (0) 2019.04.18