전체 코드

🚀 1. 개요

C++11부터 도입된 중괄호 {} 초기화는 초기화 방식의 일관성을 제공하고, 축소 변환 방지 등의 장점을 가집니다.
이 문법을 활용하면 기존의 다양한 초기화 방식(=, ())을 더 직관적으로 표현할 수 있으며, 벡터(vector) 등의 컨테이너 초기화에도 유용합니다.

이 문서에서는 중괄호 초기화의 필요성, 장점, 단점, 활용법을 정리하고, 예제 코드와 함께 분석하겠습니다.


📂 2. 코드 분석

🔹 클래스 정의

#include <iostream>
#include <vector>
using namespace std;

class Knight {
public:
    Knight() { }  // 기본 생성자

    Knight(int a, int b) { 
        cout << "Knight(int, int)" << endl; 
    }

    // 중괄호 초기화가 호출하는 생성자 (우선순위 높음)
    Knight(initializer_list<int> li) { 
        cout << "Knight(initializer_list)" << endl; 
    }
};

클래스 Knight의 생성자
1. Knight() → 기본 생성자
2. Knight(int, int) → 두 개의 int를 받는 생성자
3. Knight(initializer_list<int>)중괄호 {} 초기화가 호출하는 생성자

  • initializer_list를 인자로 받으면, 중괄호 {} 초기화 시 가장 우선적으로 호출됨

🎯 기본 초기화 예제

int main()
{
    // 다양한 초기화 방식
    int a = 0;    // 일반적인 대입 초기화
    int b(0);     // 소괄호 초기화
    int c{ 0 };   // 중괄호 초기화
}

다양한 초기화 방법

  • = : 일반적인 대입 초기화
  • () : 생성자 호출을 통한 초기화
  • {} : C++11 이후 지원되는 중괄호 초기화

🎯 c{ 0 };의 장점

  • 축소 변환 방지
  • 일관된 문법 제공

🔹 객체 복사 및 대입

    Knight k1;      // 기본 생성자 호출
    Knight k2 = k1; // 복사 생성자 (대입 연산자가 아님)

Knight k2 = k1;

  • 복사 생성자를 호출하여 k2k1으로 초기화 (대입 연산자가 아님)

    Knight k3;  // 기본 생성자
    k3 = k1;    // 대입 연산자 호출

k3 = k1;

  • k3를 기본 생성자로 생성한 후, k1의 데이터를 복사
  • 대입 연산자(=)가 호출됨

    Knight k4{ k2 };

Knight k4{ k2 };

  • 복사 생성자가 아닌 initializer_list를 받을 수도 있음
  • initializer_list 생성자가 없으면 복사 생성자가 호출됨

🎯 컨테이너와 중괄호 초기화

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

기존 방식 (C++98 스타일)

  • push_back()을 이용하여 벡터에 데이터를 추가

    vector<int> v2(10, 1); // 크기 10, 모든 값 1

소괄호 초기화 (생성자 방식)

  • 10개의 요소를 가지며, 모두 1로 초기화

    vector<int> v3{ 1, 2, 3, 4 };

중괄호 {} 초기화 (추천)

  • 벡터를 배열처럼 초기화 가능
  • 가독성이 좋고 직관적

🎯 축소 변환 방지

    int x = 0;
    // double y{ x };  // 에러 발생 (축소 변환 방지)

{} 초기화는 데이터 손실을 막기 위해 축소 변환을 허용하지 않음

  • intdouble 변환은 데이터 손실 가능성이 있으므로 컴파일 에러 발생

🎯 중괄호 초기화와 기본 생성자의 차이

    Knight k5();  // ⚠️ 이 코드는 함수 선언!
    Knight k6{ }; // ✅ 기본 생성자 호출

Knight k5();

  • 기본 생성자가 호출될 것 같지만, 실제로는 함수 선언
  • 이를 방지하려면 {} 사용Knight k6{ };

🎯 중괄호 초기화의 단점

    Knight k7{ 1, 2 }; // `initializer_list<int>` 생성자가 호출됨
    Knight k8(1, 2);   // `Knight(int, int)` 생성자가 호출됨

중괄호 초기화 시 initializer_list 생성자가 우선 호출됨

  • Knight k7{ 1, 2 };initializer_list<int> 호출
  • Knight k8(1, 2);Knight(int, int) 생성자가 호출됨

🎯 해결 방법

    Knight k9(1, 2); // 소괄호를 사용하면 명확하게 `Knight(int, int)` 호출
  • 소괄호 초기화를 사용하면 원하는 생성자 호출 가능

🎯 중괄호 초기화를 사용할지 여부

  1. 소괄호 () 초기화 (기본 추천)

    • 기존 C++ 스타일 유지
    • 거부감이 적음
    • vector<int>(10, 1);처럼 특정 생성자를 호출할 때 필요
  2. 중괄호 {} 초기화

    • 컨테이너 초기화에 유용 (vector<int> v{1, 2, 3, 4};)
    • 축소 변환 방지 (double d{intVal}; → 컴파일 에러)
    • 헷갈리는 함수 선언 방지 (Knight k6{}; → 생성자 호출 명확함)
    • 그러나, initializer_list 생성자가 우선 호출됨에 유의

profile
李家네_공부방

0개의 댓글