C++ 초기화 리스트에 관해서...

2006-07-13 신영진

질문>

C++ 클래스 멤버에 대한 질문이 하나 있습니다. 당신의 칼럼에서 이러한 코드들을 많이 보았습니다.

그리고 다른 곳에서 난 이러한 방식으로 사용되어진 코드를 보았습니다.

몇몇 나의 동료들은 두번째 방법의 메소드가 더 좋다고들 이야기합니다. 그러나 아무도 왜 그런지는 알지 못합니다. 클래스 멤버를 초기화하는 위의 두가지 메소드의 차이점을 알수 있을까요?

답변>

기술적으로 당신의 친구의 말이 맞습니다. 그러나 대부분의 경우 그것은 차이가 없습니다.

두번째 문법을 사용하는데는 두가지 이유가 있습니다. 한가지는 필요성이고, 다른것은 효율성입니다.

첫번째 이유인 필요성을 시험해 보도록합시다 클래스 내지는 스트럭처인 클래스 멤버를 당신이 가지고 있다고 가정해 봅시다. 그리고 이 클래스는 인자가 필요한 한 개의 생성자 만을 가지고 있습니다.

CMember는 명시된 생성자를 가지고 있으므로, 컴파일러는 디폴트 생성자(인자가 없어도 되는)를 생성하지 않습니다 그리고 CMember를 정수 인자없이 만드는 방법은 없습니다.

당신은 어떻게 다른 클래스의 멤버로 있는 CMember를 초기화 할수 있을까요? 당신은 반드시 멤버 초기화 리스트를 사용해야 합니다.

m_member로 인자를 넘기는 다른 간단한 방법은 없습니다.

멤버가 상수 오브젝트이거나 레퍼런스인 경우도 마찬가지 입니다. C++의 문법에 따르면, 상수 오브젝트 내지는 레퍼런스는 할당될 수 없습니다. 단지 초기화 될수 있습니다.

초기화 리스트를 사용하는 두번째 이유인, 효율성은 멤버 클래스가 할당 연산자와 마찬가지로 디폴트 생성자를 가지고 있는 경우에 발생합니다.

MFC CString은 완벽한 예제를 제공합니다. CString 멤버 m_str을 가지고 있는 CMyClass가 있는 상황에서 당신은 m_str을 “yada yada”로 초기화 시키고 싶어한다고 가정해 봅시다. 당신에게는 두가지 선택이 있습니다.

또는

이 두 메소드간에 차이가 존재할까요? 당연히 존재합니다.

컴파일러는 항상 모든 멤버 오브젝트가 생성자가 실행되기 이전에 초기화 된다고 가정합니다. 그러므로 첫번째 예제에서는 컴파일된 코드는 할당 구문에 도달하기 전에 m_str을 초기화 시키기 위해서 CString::CString을 호출합니다. 두번째 예제에서는 컴파일러는 CString::CString(LPCTSTR)로 “yada yada”를 스트링으로 넘기는 코드만 실행합니다. 첫번째 예제의 결과는 두번의 CString 함수가 호출되는 것 입니다.(생성자와 할당연산자), 반면에 두번째 예제에서는 단지 한 개의 함수만이 호출됩니다.

CString의 경우에는 거의 문제가 되지 않습니다. 왜냐하면 디폴트 생성자가 인라인 함수이고 CString은 단지 필요할 때 사용할 공간을 할당하기 때문입니다. 그러나 일반적으로 중복된 함수 호출은 낭비입니다. 특히 생성자와 할당 연산자에서 메로리를 할당하는 경우에는 낭비가 더 심합니다. 몇몇 큰 클래스에서는 생성자와 할당 연산자 모두 동일한 대규모 메모리를 할당하는 Init함수를 호출하는 경우도 있습니다. 그런 특수한 경우에는 불필요한 공간이 할당되는 것을 막기 위해서 반드시 초기화 리스트를 사용해야 합니다.

기본 타입인 int나 long또는 다른 타입에 대해서는 생성자가 없습니다. 그러한 경우에는 생성자에서 할당을 하거나 초기화 리스트를 사용해서 초기화를 하거나 성능상의 차이가 전혀 없습니다. 두경우 모두 한 개의 할당문이 실행 될 것입니다. 몇몇 프로그래머는 단지 습관을 들이기 위해서 항상 초기화 리스트를 사용해야 한다고 주장합니다. 그러나 전 필요에 따른 두가지 방법 사이의 전환에 어려움을 느낀적이 없습니다. 스타일적 측면에서, 전 함수 내에서 할당하는 것을 좋아합니다. 왜냐하면 코멘트와 포맷팅을 위한 여유 공간이 있고, 다음과 같이 사용할 수 있기 때문입니다.

또는

두번째 코드 조각은 확실히 객체지향이 아니라는 점을 알아야 합니다.

반면에 , 한가지 주의해야 할 독특한 기능이 있습니다. C++은 클래스 멤버를 선언된 순서대로 초기화 합니다. 초기화 리스트의 순서대로 초기화 하지 않습니다.

위의 코드에서 m_y=i가 먼저 할당되고 m_x=m_y가 실행되어서 m_x와 m_y의 값이 같다고 생각할수 있습니다.

그러나 컴파일러는 m_x를 처음으로 그리고 m_y를 초기화 합니다. 왜냐하면 그것들이 선언된 순서가 그렇기 때문입니다.그 결과는 m_x는 예측하지 못할 쓰레기 값을 가지게 됩니다. 나의 예제는 그점을 지적하기 위해 부자연스럽게 보입니다. 그러나 이러한 버그들은 항상 자연스럽게 일어납니다. 그것을 피하는 대는 두가지 방법이 있습니다. 항상 초기화하고 싶은 순서대로 선언하거나 초기화 리스트를 사용하기로 결정했다면, 항상 선언된 순서와 동일하게 사용하는 것입니다. 이것이 아마도 혼동을 피하는데 도움이 될 같습니다.

이 문서는 MSDN의 내용을 번역한 것 입니다. 원문은 http://msdn.microsoft.com/msdnmag/issues/0400/c/default.aspx 에서 보실 수 있습니다.