Uniform initialization
Modern C++ 을 사용하면서 쉽게 지나치기 쉬운 새로운 기능들
중괄호 초기화
객체 초기화 방식
C++11에서 객체를 초기화하는 방법
1 | int x( 0 ); |
객체의 초기화 과정에서 '='를 사용하는 초기화는 할당연산자(assignment operator)가 아닌 복사생성자(copy constructor)를 호출한다.
Uniform Initialization
C++11에서 중괄호({}
)를 이용한 균일초기화를 도입하였다.
1 | // 1, 3, 5 요소를 갖는 벡터 |
균일초기화는 C++에서 지원하는 세 가지 초기화 표현식(=
, ()
, {}
) 중 유일하게 어디든 사용할 수 있다.
균일초기화는 implicit narrowing conversion을 방지한다.
1 | double x, y, z; |
균일초기화는 most vexing parse에서 자유롭다.
1 | Widget w1(10); // Widget의 생성자 호출 |
균일초기화는 std::initializer_list
를 매개변수로 하는 생성자를 우선으로 호출한다.
1 | class Widget |
1 | class Widget |
다른 적절한 생성자가 있어도 std::initializer_list
를 인자로 하는 생성자가 있다면 해당 생성자를 호출한다.
1 | class Widget |
균일초기화의 인수 형식들을 std::initializer_list
안의 형식으로 변환하는 방법이 아예 없을때만 다른 생성자를 호출한다.
1 | class Widget |
중괄호안의 인수들을 std::string
으로 변환할 수 없으므로 이 경우에는 세 번째 생성자는 무시된다.
빈 중괄호 쌍은 빈std::initializer_list
가 아닌 인수 없음을 뜻한다.
1 | class Widget |
비어있는 std::initializer_list
를 인수로하는 std::initializer_list
생성자를 호출하려면 중괄호를 중괄호를 감싼다.
1 | Widget w1( {} ); // 두 번째 생성자 호출 |
템플릿의 경우 선언시점에 {}
와 ()
중 어떤것을 사용해야 하는지 판단할 수 없다.
1 | template <typename T, typename ...Args> |
doSomthing
의 localObj1
은 값이 20인 요소 10개를 갖는 벡터이고, localObj2
는 값이 10, 20인 2개의 요소를 갖는 벡터이다. 따라서 위와 같은 템플릿을 작성하는 경우 해당 내용을 문서화 해야 한다.
결론
- 클래스를 작성할 때
std::initializer_list
를 받는 생성자를 추가한다면, 클라이언트 코드가 해당 생성자를 의도치 않게 호출할 수 있다는 것을 생각해야 한다. - 객체를 초기화할 때 괄호와 중괄호의 차이점을 알고 선택해야 한다.
- 템플릿을 작성할 때 괄호와 중괄호에 따라 결과가 달라진다면, 내부 구현에대해서 문서화할 필요가 있다.
References
Uniform initialization
https://joyusgim.github.io/2022/06/18/Uniform-initialization/