C++11 이전의 초기화에는 다양한 방법이 사용되었습니다.
동일하지 않은 초기화 방식으로 복잡한 C++ 문법을 더 복잡하게 만들었습니다.
C++11에서는 {...}(braced-init-list)를 사용한 동일한 초기화 문법을 제공합니다.
기존에는 구조체나 구조체 배열 등의 경우 다음과 같이 {...}의 리스트로 초기화가 가능했습니다.
#include <iostream> using namespace std; struct MyData { int myInt; double myDouble; }; int main() { MyData data[3] = { {1, 3.3}, {2, 4.4}, {3, 10.1} }; cout << data[1].myInt << endl; cout << data[2].myDouble << endl; return 0; }
구조체의 배열을 중첩된 braced-init-list로 초기화를 하는 방법입니다.
다만 POD(Plain Old Data) 타입 만을 한정적으로 지원하기 때문에 사용에 제약이 있습니다.
std::vector나 std::list를 원하는 값으로 초기화해서 생성하는 방법 등은 제공되지 않았습니다.
C++11에서는 std::initializer_list가 추가되면서 균등한 초기화 방식을 사용할 수 있습니다.
std::initializer_list<T> 객체는 const T 타입 배열에 액세스를 제공하는 경량 프록시 오브젝트입니다.
다음 상황에서 std::initializer_list가 자동으로 생성됩니다.
1. 함수 호출 초기화와 대입 표현식을 포함해서 리스트 초기화에서 braced-init-list를 사용하는 경우
2. Ranged for에서 사용을 포함한 auto에 바인드 되는 경우
std::initializer_list는 두 개의 포인터 혹은 하나의 포인터와 크기를 이용해서 구현이 될 수 있습니다.
주의할 점은 얕은 복사로 std::initializer_list의 복사가 이뤄진다는 점입니다.
원본 초기화 리스트 객체가 파괴되면 복사된 initializer_list의 데이터 무결성을 보장할 수 없습니다.
그리고 초기화자 리스트는 하향 초기화(narrowing conversion)는 오류가 발생할 수 있습니다.
하향 초기화는 int 타입에 double 등의 타입으로 초기화하는 경우입니다.
std::initializer_list를 통해서 {...}(braced-init-list)로 균일한 초기화는 다음과 같이 사용할 수 있습니다.
#include <vector> #include <initializer_list> #include <iostream> template <class T> struct S { std::vector<T> v; S(std::initializer_list<T> l) : v{ l } { std::cout << "constructed with a " << l.size() << "-element list\n"; } void append(std::initializer_list<T> l) { v.insert(v.end(), l.begin(), l.end()); } std::pair<const T*, std::size_t> c_arr() const { return{ &v[0], v.size() }; // return 에서 리스트 초기화로 복사 // std::initializer_list를 사용하진 않음 } }; template <typename T> void templated_fn(T) {} int main() { S<int> s = { 1, 2, 3, 4, 5 }; // initializer_list로 생성 s.append({ 6, 7, 8 }); // 함수 호출에서 리스트 초기화 std::cout << "The vector size is now " << s.c_arr().second << " ints:\n"; for (auto n : s.v) std::cout << n << ' '; std::cout << '\n'; std::cout << "Range-for over brace-init-list: \n"; for (int x : {-1, -2, -3}) // ranged-for에서 auto 타입(initializer_list)으로 바인딩되서 동작 std::cout << x << ' '; std::cout << '\n'; auto al = { 10, 11, 12 }; // auto의 특별한 생성 규칙 std::cout << "The list bound to auto has size() = " << al.size() << '\n'; // templated_fn({1, 2, 3}); // compiler error! "{1, 2, 3}" is not an expression, // it has no type, and so T cannot be deduced templated_fn<std::initializer_list<int>>({ 1, 2, 3 }); // OK templated_fn<std::vector<int>>({ 1, 2, 3 }); // also OK return true; }
생성자에서 멤버를 초기화 할 때도 braced-init-list로 초기화를 합니다.
구조체에 std::vector가 존재하는데 바로 initializer_list로 초기화가 되며 함수 호출도 됩니다.
c_arr()을 보면 std::pair 형태로 braced-init-list로 바로 생성할 수 있습니다.
ranged based for문에서도 {...}가 auto(std::initializer_list)에 바인딩됩니다.
다만 주석 처리된 부분을 해제하면 에러가 발생하는데 braced-init-list 자체가 표현식이나 타입이 아니기 때문입니다.
타입이나 표현식이 아니라 템플릿 T의 타입 추론을 할 수 없습니다.
C++11의 {...}(braced-init-list)를 통해서 편리하고 직관적인 초기화가 가능해졌습니다.
'Programming > CPP11&14' 카테고리의 다른 글
[C++11] 배열을 편리하게 사용할 수 있는 std::array (0) | 2017.08.26 |
---|---|
[C++11] 가중치를 적용해서 랜덤 넘버(Random Number) 생성 (0) | 2017.01.05 |
[C++11] Storage class specifiers에 thread_local 추가 (0) | 2015.07.07 |
[C++11] std::mutex를 통한 thread 동기화 (0) | 2015.06.29 |
[C++11] thread 지원 - future를 통한 return값 획득 (2) (0) | 2015.06.28 |