effective c++ & c++

ch01-4. 객체를 사용하기 전에 객체를 반드시 초기화하자.

공대녀J 2022. 9. 6. 21:52

객체 초기화 규칙 

 

- 비멤버 객체,기본제공 타입의 객체에 대해서는 손수 초기화 수행 필요.

- 생성자에서는 그 객체 내의 모든 것을 초기화해준다.

- 생성자에서 객체 내 모든 것을 초기화 시켜줄 때에는 이니셜라이저를 사용.

- 비지역 정적 객체를 지역 정적 객체로 바꾸어, 여러 번역 단위에 있는 비지역 정적 객체들의 초기화 문제를 피하자.

 

 

 

어떤 객체이든 그 객체의 데이터 멤버는 생성자의 본문이 실행되기 전에 초기화되어야 한다.

즉, 생성자에서 대입 연산자를 통해 초기화되는 것은 '대입'이지 '초기화'가 아니다.

- 생성자에서 대입 연산자보다 이니셜라이저(= 멤버 초기화 리스트)를 통해 멤버를 초기화해준다.

 

윤성우의 열혈 C++ 프로그래밍 책에서는 '멤버 이니셜라이저'라 칭하고

Effective C++ 책에서는 멤버 초기화 리스트를 사용한다고 되어 있는데 동일한 의미인 것 같다.

 

* 매개변수가 없는 생성자에서 멤버를 초기화하는 방법

class ABEntry
{
private:
	string theName;
    string theAddress;
    list<PhoneNumber> thePhones;
    int numTimesConsulted;
public:
	ABEntry():theName(),theAddress(),thePhones(),numTimesConsulted(0)
    {}
};

 기본제공 타입(예. int)의 멤버를 초기화가 의무적으로 이루어져야 하는 경우

1. 상수일 경우

2. 참조자일 경우

 

데이터 멤버의 초기값을 파일에서 읽어오는 경우나, 데이터베이스에서 찾아오는 경우에는

private 지정자에 대입 연산자를 활용하여 데이터 멤버들을 초기화하는 별도의 함수를 구현한 뒤,

생성자에서 이를 호출하는 방법을 사용하면 유용하다.

 

 

 

객체를 구성하는 데이터의 초기화 순서

 

1. 기본 클래스가 파생 클래스보다 먼저 초기화

2. 클래스 데이터 멤버는 그들이 선언된 순서대로 초기화

-> 이니셜라이저를 수행할 때도 선언된 순서로 해주어야 한다.

 

 

 

비지역 정적 객체의 초기화 순서는 개별 번역 단위에서 정해진다.

즉, 서로 다른 번역 단위에 정의된 비지역 정적 객체들 사이의 상대적인 초기화 순서는 정해져 있지 않다.

 

* 정적 객체 : 생성된 시점부터 프로그램이 끝날 때까지 살아 있는 객체.

(= 프로그램 실행이 끝날 때 소멸자가 호출되어 자동으로 소멸된다.)

정적 객체라 칭할 수 있는 것들에는 5가지가 있다.

1. 전역 객체

2. 네임스페이스 유효범위에서 정의된 객체

3. 클래스 내부에서 static으로 선언된 객체

4. 함수 내부에서 static으로 선언된 객체

5. 파일 유효범위에서 static으로 정의된 객체

 

함수 내부의 정적 객체를 지역 정적 객체라 하고, 그 외의 정적 객체는 비지역 정적 객체라 한다.

 

* 번역 단위 : 컴파일을 통해 하나의 오브젝트 파일을 만드는 바탕이 되는 소스 코드.

소스 파일과 #include 하는 파일들이 합쳐져서 하나의 번역 단위가 된다.

 

따라서 한쪽 번역 단위에 있는 비정적 객체의 초기화가 진행될 때 다른 쪽 번역 단위의 비지역 정적 객체가 사용되는 경우,

다른 쪽 정적 객체가 초기화 되어 있지 않을 수도 있다는 문제점이 발생할 수 있다.

class FileSystem
{
public:
	size_t numDisks() const;
    ...
};

extern FileSystem tfs;
class Directory
{
public:
	Directory(params);
    ...
};

Directory::Directory(params)
{
	size_t disks=tfs.numDisks();
}

이 문제를 사전에 봉쇄하기 위한 방법으로

'비지역 정적 객체를 하나씩 맡는 함수를 준비하고 이 안에 각 객체를 넣기' 가 있다.

- 함수 내에서 이들을 정적 객체로 선언 -> 비지역 정적 객체를 직접 참조하지 않는다.

- 함수의 반환 값을 이에 대한 참조자로 한다.

 

이를 통해 비지역 정적 객체를 지역 정적 객체로 변경할 수 있으며,

지역 정적 객체는 함수 호출 중 객체의 정의를 최초로 마주쳤을 때,

그 객체를 초기화하도록 되어 있음을 활용하여 초기화된 정적 객체를 참조할 수 있도록 한다.

FileSystem& tfs()
{
	static FileSystem fs;
    return fs;
}

class Directory
{ ...};

Directory::Directory(params)
{
	size_t disks=tfs().numDisks(); // 객체에 대한 참조자를 반환하는 함수 사용.
}

이러한 아이디어는 개발자가 객체들의 초기화 순서를 제대로 맞춰 둔다는 전제조건이 뒷받침되어 있어야 한다.