뚜둔뚜둔✩

판다의 개발일지

C · C++

[C++] 초기화 (Initialization)

2022. 5. 25. 00:40

    대입과 초기화

    대입 (Assignment)

    대입은 = 대입 연산자를 사용하여 어떤 변수에 값을 지정하는 것이다. 이를 "copy assignment"라고도 하는데, 그 이유는 대입은 등호 왼쪽의 객체(변수)에 등호 오른쪽의 값을 복사하는 행위이기 때문이다. 하지만 그렇기 때문에 연산자 왼쪽의 객체(변수)가 이미 정의/생성되어 있어야 한다.

    초기화 (Initialization)

    반면, 초기화는 객체의 생성과 함께 최초의 설정값을 지정하는 것이다. 따라서 함수 호출의 회수가 대입에 비해 적으며 더 빠르기도 하다. 초기화로는 상수(const) 변수의 값 설정 또한 가능하다.

     

    초기화의 방식

    class Point
    {
    public:
    	Point(int x_val, int y_val)
        {
        	x = x_val; y = y_val;
        }
    private:
    	int x;
        int y;
    };

    Copy Initialization

    Point p1 = { 0, 1 };

    등호(=)를 사용한 초기화이다. 대입과 마찬가지로 등호 오른쪽의 값을 등호 왼쪽의 객체(변수)에 복사한다. int와 같이 단순한 타입의 변수에는 문제없으나, 타입이 복잡해지면 복사의 방식이 비효율적이다.

    Direct Initialization

    Point p2( 2, 3 );

    소괄호(( ))를 사용한 초기화이다. 단순한 타입의 초기화에는 copy initialization와 다를 바 없으나, 복잡한 타입의 초기화에는 direct initialization이 더 효율적이다.

    Brace Initialization (Uniform Initialization)

    Point p3 { 4, 5 };

    중괄호({ })를 사용한 초기화이다.

    소괄호를 사용한 direct initialization은 모든 데이터 타입을 초기화 하는데에 사용할 수 없다. 따라서 C++에서는 모든 형태의 변수를 초기화 할 수 있는, uniform initialization을 통한 초기화 방법을 제공한다.

    int main(void)
    {
    	int v1 = 0;
    	int v2{ 1 };
    	int v3( 2 );
    
    	int arr_v1[2] = { 0, 1 };
    	int arr_v2[2]{ 2, 3 };
    	int arr_v3[2]( 4, 5 );
    
    	return 0;
    }
    main.cpp:11:6: error: array initializer must be an initializer list
            int arr_v3[2]( 4, 5 );
                ^
    1 error generated.

     

    Uniform Initialization

    초기화의 형태

    uniform initialization의 사용은 크게 3가지 형태로 구분된다.

     

    1) direct brace initialization (권장)

    int var { 0 };

    2) copy brace initialization

    int var = { 0 };

    3) value initialization

    int var { };	// value initialization

    value initialization은 인자 없는 생성자를 호출하며 객체를 생성한다. 따라서, 컴파일러가 제공하는 default 생성자 또는 사용자가 직접 정의한, 인자가 없는 생성자를 호출할 수 있어야 한다.

    class t1
    {
    private:
    	int var;
    };				// implicit default constructor
    
    class t2
    {
    public:
    	t2() { }	// user-provided default constructor
    private:
    	int var;
    };
    
    class t3
    {
    public:
        			// no default constructor
    	t3(int val) { var = val; }
    private:
    	int var;
    };
    
    int main(void)
    {
    	t1 var1{ };
    	t2 var2{ };
    	t3 var3{ };
    }
    main.cpp:27:5: error: no matching constructor for initialization of 't3'
            t3 var3{ };
               ^   ~~~
    1 error generated.

    데이터 손실의 방지

    uniform initialization은 또 다른 기능도 있다. 바로 "preventing narrowing conversion"이다. 이는 결국 어떤 변수에 해당 변수가 저장할 수 있는 크기보다 더 큰 크기의 데이터를 저장하여 일부 데이터의 손실이 발생하는 것을 방지한다.

    int main(void)
    {
    	int var { 4.5 };
    }
    main.cpp:3:12: error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]
            int var { 4.5 };
                      ^~~
    1 warning and 1 error generated.

     

     

    References

    https://en.cppreference.com/w/cpp/language/value_initialization

     https://www.learncpp.com/cpp-tutorial/variable-assignment-and-initialization/