12.6 Constructor member initializer lists

주홍영·2022년 3월 17일
0

Learncpp.com

목록 보기
130/199

https://www.learncpp.com/cpp-tutorial/constructor-member-initializer-lists/

우리는 const variable은 declare와 동시에 initialize가 되어야 한다는 것을 배웠다
그렇다면 일반적으로 constructor를 사용하는 경우에 어떤일이 벌어질까?

class Something
{
private:
    const int m_value;

public:
    Something()
    {
        m_value = 1; // error: const vars can not be assigned to
    }
};

우리는 앞선 섹션에서 constructor가 member variable을 모두 생성하고
initialzie 한다는 것을 알 수 있었다
그렇다면 위와 같은 경우에는 오류가 발생할 것이다
왜냐하면 const variable을 declare와 동시에 initialize를 하지 않기 때문에

위의 문제는 어떻게 해결해야 할가?

Member initializer lists

c++ 에서 클래스의 member variable을 declare와 동시에 값을 할당하기 위해서 다음과 같은 방법이 있다

class Something
{
private:
    const int m_value;

public:
    Something(): m_value{ 5 } // directly initialize our const member variable
    {
    }
};

Something constructor 에 옆에서 initialize를 진행할 수 있다
따라서 위의 const variable은 더 이상 오류가 발생하지 않느다

Initializing array members with member initializer lists

array member도 다음과 같이 initialize할 수 있다

class Something
{
private:
    const int m_array[5];

public:
    Something(): m_array {} // zero the member array
    {
    }

};

하지만 c++11이전에는 위와 같이 zero init 밖에 불가능했다
하지만 c++11 부터는 fully initialize할 수 있다

class Something
{
private:
    const int m_array[5];

public:
    Something(): m_array { 1, 2, 3, 4, 5 } // use uniform initialization to initialize our member array
    {
    }

};

Initializing member variables that are classes

클래스 member variable도 init 할 수 있다

#include <iostream>

class A
{
public:
    A(int x = 0) { std::cout << "A " << x << '\n'; }
};

class B
{
private:
    A m_a {};
public:
    B(int y)
        : m_a{ y - 1 } // call A(int) constructor to initialize member m_a
    {
        std::cout << "B " << y << '\n';
    }
};

int main()
{
    B b{ 5 };
    return 0;
}

위 코드의 출력은 다음과 같다

A 4
B 5

Formatting your initializer lists

우리는 다양한 방법으로 init list를 작성할 수 있다

class Something
{
private:
    int m_value1 {};
    double m_value2 {};
    char m_value3 {};

public:
    Something() : m_value1{ 1 }, m_value2{ 2.2 }, m_value3{ 'c' } // everything on one line
    {
    }
};

위의 코드에서는 한 라인에 모두 list가 모두 존재한다

class Something
{
private:
    int m_value1;
    double m_value2;
    char m_value3;

public:
    Something(int value1, double value2, char value3='c') // this line already has a lot of stuff on it
        : m_value1{ value1 }, m_value2{ value2 }, m_value3{ value3 } // so we can put everything indented on next line
    {
    }

};

위의 코드에서는 다음 라인으로 indentation과 함께 list를 작성하고 있다

class Something
{
private:
    int m_value1 {};
    double m_value2 {};
    char m_value3 {};
    float m_value4 {};

public:
    Something(int value1, double value2, char value3='c', float value4=34.6f) // this line already has a lot of stuff on it
        : m_value1{ value1 } // one per line
        , m_value2{ value2 }
        , m_value3{ value3 }
        , m_value4{ value4 }
    {
    }

};

위의 코드와 같이 line에 하나의 변수씩 init하는 것도 가능하다

Initializer list order

member variable이 declare된 순서대로 init list를 작성할 필요는 없다
하지만 그렇게 하지 않으면 컴파일러 경고를 줄 수도 있다
그리고 순서를 뒤죽박죽 작성할 이유도 없다

그리고 서로 dependency를 가지도록 init하지 말자
참고로 declare된 순서대로 (initialize list 순서대로가 아닌)
init list의 명령대로 initialize가 진행된다
따라서 dependency를 만들 수가 있다
하지만 그렇게 하지 말라는 소리다

#include <iostream>
class Something
{
private:
     int m_value1;
     int m_value2;

public:
    Something() :  m_value1{ 2 }, m_value2{ m_value1 }
    {
       
    }
};

위와 같이 코딩하면 m_value2{m_value1}이 올바르게 들어가긴 한다
그런데 만약 반대로 하면 쓰레기 값이 들어간다

#include <iostream>
class Something
{
private:
     int m_value1;
     int m_value2;

public:
    Something() :  m_value2{ 2 }, m_value1{ m_value2 }
    {
       
    }
};

위와 같이 작성하면 m_value1에 쓰레기 값이 들어간다는 것이다
왜냐하면 list 순서가 아닌 declare 순서대로 init을 하기 때문에...

Summary

Member initializer lists allow us to initialize our members rather than assign values to them.
assign을 통한 초기화가 아닌 initialization을 할수 있게 됐음
member init list 덕분에
이는 constructor를 활용해 initialize하는 유일한 방법이다 (declare 후 assign이 아닌)

profile
청룡동거주민

0개의 댓글