스콧 마이어스의 Effective C++을 읽고 개인 공부 목적으로 요약 작성한 글입니다!
💡 기본제공 타입의 객체는 직접 손으로 초기화한다! (경우에 따라 자동 초기화 유무 바뀜)
💡 생성자에서는 멤버 초기화 리스트를 사용해서 초기화하자!
(초기화 리스트에 데이터 멤버를 나열할 때는 각 데이터 멤버의 선언 순서와 동일하게!!)
💡 여러 번역 단위에 있는 비지역 정적 객체들의 초기화 순서 문제는 피해서 설계하자
-> 비지역 정적 객체를 지역 정적 객체로 변경!
초기화하지 않은 값을 읽어버리면 정의되지 않은 값이 그대로 나옴
초기화가 될거란 보장이 없다 ㅠㅠ
제발 모든 객체를 사용하기 전에 항상 초기화하자!
class PhoneNumber { ... };
class ABEntry {
public:
ABEntry(const string& name, const string& address, const list<PhoneNumber>& phones);
private:
string theName;
string theAddress;
list<PhoneNumber> thePhones;
int numTimesConsulted;
};
ABEntry::ABEnrty(const string& name, const string& address, const list<PhoneNumber>& phones)
{
theName = name;
theAddress = address;
thePhones = phones;
numTimesConsulted = 0;
}
마 장난하나
이건 대입이지
어떤 객체이든 객체의 데이터 멤버는 생성자 본문이 실행되기 전에 초기화되어야 함
그니까 생성자 본문에서 theName, theAddress, thePhones, numTimesConsulted는 이미 디폴트 생성자를 호출해서 초기화되어있고, 생성자 본문에서 걍 새로운 값을 대입하는 거..
(디폴트 생성자 + 복사 대입 연산자 호출)
대입 연산을 하나의 private 함수에 몰아놓고 모든 생성자에서 이 함수를 호출하는 방식으로,,
파일이나 DB에서 진짜 초기값을 읽어올 때 이렇게 사용하기도 한당
ABEntry::ABEnrty(const string& name, const string& address, const list<PhoneNumber>& phones)
: theName(name),
theAddress(address),
thePhones(), // 디폴트 생성자로 초기화할때도 초기화는 하셈
numTimesConsulted(0)
{}
초기화 리스트에 들어가는 인자는 데이터 멤버에 대한 생성자의 인자로 쓰인다!
(복사 생성자 호출)
: 자신이 생성된 시점부터 프로그램이 끝날 때까지 살아있는 객체
지역 정적 객체 : 함수 안에 있는 정적 객체
비지역 정적 객체 : 나머지
: 컴파일을 통해 하나의 목적 파일을 만드는 바탕이 되는 소스코드
기본적으로 소스 파일 하나..
#include하는 파일들까지 합쳐서 하나의 번역 단위
이 비지역 정적 객체가 초기화되어 있지 않을 수도 있다 ㅠㅠ!
class FileSystem {
public:
...
std::size_t numDisks() const;
...
};
extern FileSystem tfs;
class Directory{
public:
Directory(params);
...
};
Directory::Directory(params)
{
...
std::size_t disks = tfs.numDisks(); // 여기서 문제
...
}
Directory tempDir (params);
이 경우에, tfs가 tempDIr보다 먼저 초기화되지 않으면
tempDir의 생성자는 tfs가 초기화되 않았는데 tfs를 사용하려고 함
-> 서로 다른 번역 단위 안에서 정의된 비지역 정적 객체들이기 때문에 이런 문제가 발생한다
비지역 정적 객체를 하나씩 맡는 함수를 준비하고 이 안에 각 객체를 넣는다. 함수 안에서 정적으로 선언하고 참조자를 반환하도록 한다.
비지역 정적 객체를 직접 호출하지 않고 함수 호출(반드시 초기화된 객체를 참조)로 대신한다!
익숙하쥬?
class FileSystem { ... };
FileSystem& tfs() { // tfs 객체 대산 tfs() 함수로 대체!
static FileSystem fs; // 함수가 클래스 안에 static 멤버로 들어가도 된다
return fs;
}
class Directory { ... };
Directory::Directory(params) {
...
std::size_t disks = tfs().numDisks();
...
}
Directory& tempDir() {
static Directory td;
return td;
}
하지만 멀티쓰레드에서 싱글톤은 정말 끔찍하다
알자너 ㅎ..
초기화 할 때는 멤버 초기화 리스트를 써서 생성자 본문이 호출되기 전에 하자.
그리고 싹 다 초기화하자 진짜 죽기 싫으면...