본문 바로가기

Effective C++

[EC++] 항목 4. 객체를 사용하기 전에 반드시 그 객체를 초기화하자

대입과 초기화를 구분하자  
  C++규칙에 의하면 어떤 객체이든 그 객체의 데이터 멤버는 생성자의 본문이 실행되기 전에 초기화 되어야 한다고 명시되어 있다. 위의 예제는 초기화가 아니라 대입이다. 초기화는 진작 지나갔다. A의 생성자에 진입하기도 전에 기본 생성자가 호출된 것이다. 하지만 num은 미리 초기화 되지 않았다. 기본제공 타입의 데이터 멤버이기 때문이다. 생성자 안에서 대입되기 전에 초기화 되리란 보장이 없다. 따라서 이런경우 아래와 같이 초기화 리스트를 사용한다.
사용자가 원하는 값을 주고 시작하는 점은 같지만, 더 효율적일 가능성이 크다. 초기화 리스트에 들어가는 인자는 바로 데이터 멤버에 대한 생성자의 인자로 쓰이기 때문이다. 기존 방법은 기본 생성자를 호출하고 복사대입 연산자를 호출하는 방식이지만 초기화 리스트를 사용하면 복사생성자를 한 번 호출하므로 더 효율적이다. 기본타입은 상관 없지만 초기화 리스트에 넣어 두는 쪽이 좋다.

 기본제공 타입의 멤버를 초기화 리스트로 넣는 일이 의무일 경우가 있다. 이것은 바로 상수이거나, 참조자로 되어 있는 데이터 멤버의 경우엔 반드시 초기화되어야 하기 때문이다. 상수와 참조자는 대입 자체가 불가능하기 때문이다.

※ 객체를 구성하는 데이터의 초기화 순서
1. 기본 클래스는 파생 클래스보다 먼저 초기화 된다. 
2. 클래스 데이터 멤버는 그들이 선언된 순서대로 초기화 된다. 

※ 비지역 정적 객체의 초기화 순서는 개별 번역 단위에서 정해진다.
 - 정적객체(static object) : 자신이 생성된 시점부터 프로그램이 끝날때 까지 살아 있는 객체.
 - 정적객체 범주에 들어가는 것
  1. 전역 객체
  2. 네임스페이스 유효범위에서 정의된 객체
  3. 클래스 안에서 static으로 선언된 객체
  4. 함수 안에서 static으로 선언된 객체
  5. 파일 유효범위에서 static으로 정의된 객체

  이들중 4번은 지역 정적 객체라고 하고, 나머지는 비지역 정적 객체라고 한다. 다섯종류 모두 프로그램이 끝날때 자동으로 소멸된다. 즉, main() 실행이 끝날때 정적 객체의 소멸자가 호출된다. 

※ 서로 다른 번역 단위에 정의된 비지역 정적 객체들 사이의 상대적인 초기화 순서는 정해져 있지 않다.  설계에 약간의 변화만 주면 이 문제를 사전에 봉쇄할수 있다. 비지역 정적 객체를 하나씩 맡는 함수를 준비... 이안에 각 각체를 넣는다. 함수속에서도 정적 객체로 선언.
  함수에서는 이들에 대한 참조자를 반환하게 만든다. 그리고 함수 호출로 대신한다. 지역 정적 객체는 함수 호출 중에 그 객체의 정의에 최초로 닿았을 때 초기화 되도록 만들어져 있다. 

 마무리...  
 - 기본제공 타입 객체는 직접 초기화 하자.
 - 객체의 모든 부분에 대한 초기화에는 멤버 초기화 리스트를 사용하자.
 - 여러 번역 단위에 있는 비지역 정적 객체들의 초기화 순서 문제는 피해서 설계하자.  -> 비지역 정적 객체를 지역 정적 객체로 바꾸면 된다.