C++11에서는 객체 생성 구문이 아주 다양해졌다.
C++ 에서는 Class 개념이 있기 때문에 초기화와 배정이 각자 다른 함수들을 호출한다.
정확하게 괄호/중괄호를 이해하고 써야하는 이유이다.
중괄화 초기화를 선호한다.
절대 여기만 보고 페이지 넘기지마세요~
초반에만 중괄호 초기화에 대한 내용을 기술하고, 후반부터는 단점을 기술한다.
장점 1: narrowing conversion을 방지
double x, y, z;
int sum1{ x + y + z}; // 오류! double들의 합을 int로 표현하지 못할 수 있음
괄호나 "="를 이용한 초기화는 이러한 좁히기 변환을 점검하지 않는다.
장점 2: 가장 성가신 구문 해석에 자유롭다는 점
가장 성가신 구문 해석은 "선언으로 해석할 수 있는 것은 항상 선언으로 해석해야 한다"는 C++의 규칙에서 비롯된 하나의 부작용 --> 사실 무슨말인지 이해가 잘 안되는 문장이었다.
Widget w1(10); // 인수 10으로 Widget의 생성자를 호출
Widget w2(); // 가장 성가신 구문 해석! Widget을 돌려주는, w2라는 이름의 함수를 선언한다.
Widget w3{}; // 인수 없이 Widget의 생성자를 호출
단점 1: 종종 예상치 못한 행동을 보인다.
중괄호 초기치와 std::initializer_list, 그리고 생성자 중복적재 해소 사이에서 발생한다.
이유는 중괄호 초기화 구문은 이상하게도 std::initializer_list를 받는 중복적재 버전을 강하게 선호한다.
class Widget{
public:
Widget(int i, bool b);
Widget(in i, double d);
Widget(std::initializer_list<long double> il);
};
Widget w1(10, true); // 첫 생성자를 호출
Widget w2{10, true}; // 중괄호를 사용한 경우, std::initializer_list 생성자 호출
Widget w3(10, 5.0); // 둘째 생성자 호출
Widget w4{10, 5.0}; // std::initializer_list 생성자 호출
std::initializer_list 생성자가 가능한 최선의 부합인 경우에도 그 생성자를 호출할 수 없는 기현상이 생기기도합니다.
class Widget{
public:
Widget(int i, bool b);
Widget(int i, double d);
Widget(std::initializer_list<bool> il);
};
Widget w{10, 5.0} // 오류!
위 코드를 보면 두 변환 모두 좁히기 변환인데, 중괄호초기화는 좁히기 변환을 허용하지 않으니 오류 발생한다.
변환하는 방법이 없으므로 다시 중복적재 해소의 후보가됩니다.
class Widget{
public:
Widget(int i, bool b);
Widget(int i, double d);
Widget(std::initializer_list<std::string> il);
};
Widget w1(10, true); // 첫 생성자를 호출
Widget w2{10, true}; // 첫 생성자를 호출
Widget w3(10, 5.0); // 둘째 생성자 호출
Widget w4{10, 5.0}; // 둘째 생성자 호출
std::vecotr만 봐도 괄호와 중괄호는 다르다.
std::vector<int> v1(10, 20); // 비 std::initializer_list 생성자를 사용 모든 요소의ㅏ 값이 20인, 요소 10 자리 std::vector 생성
std::vector<int> v2{10, 20}; // 값이 각각 10과 20인 두 요소를 담은 std::vector 생성
그래서 뭘 쓰라는거야?가 중요한게 아니다
정리하자면,
첫째, 클래스를 작성할 때, 만일 일단의 중복적재된 생성자 중에 std::initializer_list를 받는 함수가 하나 이상 존재한다면, 중괄호 초기화 구문을 이용하는 코드에는 std::initializer_list 중복적재들만 적용될 수 있음을 주의해야한다.
둘째, 객체를 생성할 때 괄호와 중괄호를 세심하게 선택
템플릿 안에서 객체를 생성할 때 괄호를 사용할 것인지 중괄호를 사용할 것인지 선택하기가 어려울 수 있다.
'서적 > Effective Modern C++' 카테고리의 다른 글
항목 8: 0과 NULL보다 nullptr를 선호하라 (0) | 2022.08.18 |
---|---|
항목 6: auto가 원치 않은 형식으로 연역될 때에는 명시적 형식의 초기치를 사용하라 (0) | 2022.07.06 |
항목 5: 명시적 형식 선언보다는 auto를 선호하라 (0) | 2022.07.04 |