여기에서 전반적인 내용은 사실 c++ 기본 문법에 관련된 사항이라 내 생각에 좀 중요하다고 생각된 부분만 정리했다.
우선 번역단위 라는 말인데. 번역단위란 간단히 말하면 소스 파일 하나라고 생각하면 된다. 또한 정적 객체란 static, extern으로 선언한 객체인것은 모두 알 것이다. 자 여기서 별개의 번역단위에서 정의된 비지역 정적 객체들의 초기화 순서는 정해져있지 않다라는 것인데. 우선 이 말을 하나하나 풀이 해보면 서로다른 파일에 정의된 비지역 즉, 함수 외부에 선언된 정적 객체들의 초기화 순서는 정해져있지 않다는 뜻이 된다. 이게 문제가 되는 이유는 바로 다음과 같은 경우이다.
// filesystem.h
class FileSystem
{
public:
...
std::size_t numDisks() const;
...
};
extern FileSystem tfs;
// directory.h
class Directory
{
public:
Directory(params);
...
};
Directory::Directory(params)
{
...
std::size_t disks = tfs.numDisks();
...
}
자 위와 같이 filesystem파일에는 FileSystem 객체가 extern으로 비지역 정적 객체로 선언된 상태이고 그 객체를 directory.h라는 파일에서 Directory클래스의 생성자에서 사용한다고 치자. 그런데 위에서도 말했듯이 비지역 정적객체의 초기화 순서는 정해져 있지 않다고 했다. 그래서 Directory클래스의 생성자가 실행될때 FileSystem객체가 초기화 되지 않았을 수도 있다는 것이다. 그러면 예상하지 못한 오류들이 터져 나올 것이다. 그렇다면 이것을 어떻게 해결 할 수 있을까?
방법은 바로 '비지역 정적 객체'를 '지역 정적 객체'로 바꾸면 된다. 사실 이를 디자인 패턴중 싱글톤 패턴(Singleton Pattern)이라고도 부른다. 이를 적용하여 위의 문제를 해결한 코드를 보자.
// filesystem.h
class FileSystem { ... }; // 이전과 동일
FileSystem& tfs()
{
static FileSystem fs;
return fs;
}
// directory.h
class Directory
{
public:
Directory(params);
...
};
Directory::Directory(params)
{
...
std::size_t disks = tfs().numDisks(); //tfs -> tfs()
...
}
자 위와 같이 별도의 함수를 만들어 함수 내에 지역 정적 객체를 선언하여 반환하도록 하면 초기화의 순서에 연연해 할 필요가 없게 된다. Directory 생성자에서 FileSystem 객체를 필요로 할 때 tfs()함수를 호출 시키면 지역 정적객체를 초기화하여 참조자를 반환시켜 주기 때문이다. 나는 이것을 보면서 느낀것은 내가 아는 싱글톤은 항상 new를 통해서 힙 영역에 객체를 생성하고 정적 함수를 통해 객체를 반환하는 식이어서 항상 메모리 해제가 필요했는데 이런식으로 Data 영역을 이용해 싱글톤 패턴을 이용할 수 있다는 점을 처음 깨달았다. 앞으로 설계할때는 아마 이 방식의 싱글톤을 애용할 듯 하다.
'C++ > Effective C++' 카테고리의 다른 글
항목 7 다형성을 가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자 (0) | 2024.01.18 |
---|---|
항목 6 컴파일러가 만들어낸 함수가 필요 없으면 확실히 이들의 사용을 금해 버리자 (2) | 2024.01.18 |
항목 3 낌새만 보이면 const를 들이대 보자! (0) | 2024.01.17 |
항목 2 #define을 쓰려거든 const, enum, inline을 떠올리자. (0) | 2024.01.17 |
Effective C++ 스타트 (0) | 2024.01.17 |