[모던 C++] 중괄호 초기화와 이니셜라이저 리스트

Jin Hur·2022년 10월 23일
0

C++

목록 보기
8/18

중괄호 초기화

예시

class Knight {
public:
	int _hp;

public:
	Knight() {
		cout << "기본 생성자 호출" << endl;
		_hp = 10;
	}
	Knight(int hp) {
		_hp = hp;
	}
	Knight(const Knight& k) {
		cout << "복사 생성자 호출" << endl;
		_hp = k._hp;
	}
	Knight& operator=(const Knight& k) {
		cout << "대입 연산자 호출" << endl;
		_hp = k._hp;
		return *this;
	}
	~Knight() {
		cout << "소멸자 호출" << endl;
	}
};

...
...

	{
		int a = 0;
		int b(0);

		// 중괄호 초기화
		int c{ 0 };

		Knight k1;	// 기본 생성자 호출을 통한 초기화 

		Knight k2 = k1;	// 복사 생성자 호출을 통한 초기화

		Knight k3;	// 기본 생성자 호출
		k3 = k1;	// 대입 연산자 호출을 통한 초기화

		Knight k4{ k1 };	// 복사 생성자 호출을 통한 초기화
		// 중괄호 초기화
		Knight k5{ k1 };	// => 내부적으로 복사 생성자 호출
    }

중괄호 초기화를 사용하는 이유

1. 다양한 초기화 방식에서 통일성을 제공

		int a = 3;
		Knight k1(5);
		int arr[] = { 1, 2, 3 };

		// 중괄호 초기화
		int b{ 4 };
		Knight k2{ 5 };
		int arr2[] = { 1, 2, 3 };

2. 초기화 방식 통일 뿐 아니라 STL 컨테이너에 또 다른 초기화 방식 제시(이니셜라이저를 통한 생성자)

벡터와 같은 컨테이너와 궁합이 좋아짐

		vector<int> vec;
		vec.push_back(1);
		vec.push_back(2);
		vec.push_back(3);

		vector<int> vec2(3, 1);

		// 중괄호 초기화
		vector<int> vec3 = { 1, 2, 3 };

3. 축소변환 방지

		int i = 2;
        // 정수 <-> 실수, 축소 변환 발생
        float f1 = i;	// 에러 발생 X
		//float f2{ i };	// 에러: int에서 float로의 변환에는 축소 변환이 일어납니다.
							// 즉, 변환하면서 데이터가 손실될 수 있습니다.
							// 중괄호 초기화를 통해 이러한 축소 변환(데이터 손실)을 방지

4. 함수 선언문 방식의 초기화 선언 방지

		// 기본 생성자 호출로 오해
        // 사실은 함수 선언에 불과
		Knight k3();	// 경고: Knight k(void) 프로토타입 함수가 호출되지 않았습니다. 변수 정의로 사용하려 한 것은 아닌지 확인하시오.
        				// 컴파일러 수준에서 경고만 발생할 뿐
		
		Knight k4{};	// 중괄호 초기화를 통해 클래스의 기본 생성자 호출

이니셜라이즈 리스트(std::initializer_list<>)

  • 중괄호 초기화를 통해 구현한 생성자들을 호출할 수 있다.
/* 이니셜라이즈 리스트 */
	class MyClass {
		int a;
		int b;
		int c;

	public:
		MyClass() {
			this->a = 1;
			this->b = 5;
			this->c = 10;
			cout << "MyClass() 호출" << endl;
		}
		MyClass(int a) {
			this->a = a;
			this->b = 5;
			this->c = 10;
			cout << "MyClass(int a) 호출" << endl;
		}
		MyClass(int a, int b) {
			this->a = a;
			this->b = b;
			this->c = 10;
			cout << "MyClass(int a, int b) 호출" << endl;
		}
		MyClass(int a, int b, int c) {
			this->a = a;
			this->b = b;
			this->c = c;
			cout << "MyClass(int a, int b, int c ) 호출" << endl;
		}


	};
	{
		MyClass myClass = { 1, 2 };
		MyClass myClass1 = { 1, 2, 3 };
		MyClass myClass2{ 1, 2, 3 };	
	}

여기서 MyClass에서 이니셜라이저를 통한 생성자를 추가한다면,

		// 이니셜라이즈 리스트를 통한 생성자
		MyClass(initializer_list<int> iniList) {
			cout << "이니셜라이즈 리스트를 통한 생성자 호출" << endl;
			auto iter = iniList.begin();
			this->a = *iter;
			this->b = *(iter + 1);
			this->c = *(iter + 2);
		}

그리고
MyClass myClass = { 1, 2 }; 호출의 경우 멤버변수 c가 쓰레기 값으로 채워진다.

0개의 댓글