Home Uniform Initialization
Post
Cancel

Uniform Initialization

Uniform Initialization

개요

C++11 이전에는 타입의 초기화 방식이 일정하지 않았다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct CircleStruct{
  int x, y;
  double radius;
};

class CircleClass{
public:
  CircleClass(int x, int y, double radius)
    : mX(x), mY(y), mRadius(radius) {}

private:
  int mX, mY;
  double mRadius;
}

...
...

  CircleStruct myCircle_1 = {10, 10, 2,.5};
  CircleClass myCircle_2(10, 10, 2.5);

c++11 이전에는 위와같은 struct 타입 변수와 class 타입 변수를 초기화할때, 서로 다른 방식으로 초기화를 했다. struct에 대해서는 {…}, class 에 대해서는 (…)을 사용하여 각자 초기화를 진행한다.

그러나 c++11 이후부터 타입을 초기화 할때, {…} 문법을 사용하는 유니폼 초기화(Uniform Initialization) 를 사용하도록 통일시켰다.

1
2
3
4
5
6
  CircleStruct myCircle_3 = {10, 10, 2,.5};
  CircleClass myCircle_4 = {10, 10, 2.5};

  // = 생략 가능
  CircleStruct myCircle_5{10, 10, 2,.5};
  CircleClass myCircle_6{10, 10, 2.5};

이러한 유니폼 초기화 는 구조체나 클래스 뿐만 아니라 c++에 있는 모든 대상을 초기화할때 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int a=3;
int b(3);
int c = {3};  // 유니폼 초기화
int d{3};     // 유니폼 초기화
int e{};      // 유니폼 초기화, e는 0이 된다.

int* pArray = new int[4]{0, 1, 2, 3};   // 동적할당 배열의 유니폼 초기화

class MyClass {
public:
  MyClass() 
    : mArray{0, 1, 2, 3} {}   // 배열형태인 클래스 멤버변수의 유니폼 초기화

private:
  int mArray[4];
};

유니폼 초기화 를 사용하면 축소 변환(narrowing) 을 방지할수 있다. c++ 에서는 암묵적으로 축소 변환될 때가 있다. 유니폼 초기화 가 아닌 이전의 방식대로 초기화를 진행한다면 컴파일러에 따라 축소 변환 될때 경고 메세지가 발생하지만, 유니폼 초기화 를 사용하여 초기화를 진행하면, 이를 컴파일러에서 에러 메세지가 발생하여 사전에 방지할 수 있도록 한다.

1
2
3
4
5
6
7
8
9
10
11
void func(int i) { /* ... */ }

int main() {
  int x = 3.14;     // int형 변수 이므로, 3.14 에서 3 으로 값이 축소변환 된다.
  func(3.14);       // func의 매개변수가 in형 이므로,
                    // 3.14 에서 3 으로 값이 축소변환 된다.


  int y = {3.14};   // 축소로 인한 에러
  func({3.14});     // 축소로 인한 에러
}

복제 리스트 초기화와 직접 리스트 초기화

유니폼 초기화 는 크게 두가지 방식이 존재한다.

  • 복제 리스트 초기화(Copy List Initialization)
    • T obj = {arg1, arg2, …};
  • 직접 리스트 초기화(Direct List Initialization)
    • T obj{arg1, arg2, …};

c++17부터는 auto 타입 추론 기능과 관련하여 복제 리스트 초기화직접 리스트 초기화 가 크게 달라졌다. c++17 이전에는 복제 리스트 초기화직접 리스트 초기화 가 모두 initializer_list<> 로 처리됬다. c++17부터 aut는 직접 리스트 초기화 에 대해 값 하나만 추론한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//---------------------
// c++17 이전
//---------------------

// 복제 리스트 초기화
auto a = {11};      // initializer_list<int>
auto b = {11, 22};  // initializer_list<int>

// 직접 리스트 초기화
auto c {11};        // initializer_list<int>
auto d {11, 22};    // initializer_list<int>

//---------------------
// c++17 이후
//---------------------

// 복제 리스트 초기화
auto a = {11};      // initializer_list<int>
auto b = {11, 22};  // initializer_list<int>

// 직접 리스트 초기화
auto c {11};        // int
auto d {11, 22};    // 원소가 너무 많다는 에러가 발생한다.


참고. Professional C++ 4/E - Marc Gregoire


This post is licensed under CC BY 4.0 by the author.