
안그래도 개인적으로 C++과 언리얼을, 조금씩, 천천히 공부하고 있었는데 마침 이런 상황에 찰떡인 프로그램이 있었다.
게임사중 게임 생태계에 대한 사회적 환원에 있어 최고를 자랑하는
아니 그 자체를 위해 설립된 법인이라고도 할 수 있는 퓨처랩의 '인디게임 개발 장학팀 2기'라는 프로그램이다.
이 프로그램에 선정되고자, 머리속의 구상으로만 머물러있던 (1인)스터디 계획의 일정과 커리큘럼을 구체화했다.
또한, 1인 참여 후 팀 빌딩을 통해 스터디원을 확보하려는 한편 혹여 같이 할 사람이 있을까 알아보다 후배들을 합류시켰다.
본 카테고리는, 원래도 업로드할 예정이긴 했지만, 이 스터디(선정 유무와 관계 없이 진행)에서도 C++의 이론적인 부분을 공부한 내용을 기록할 것이다. 교재는 Game Programming patterns.
Game Programming Patterns - Singleton Patterns
싱글턴 패턴은 그 의도와는 달리, 장점보단 단점이 더 많다.
-> 면접보러 갈 때 마다 기억 안나면 싱글턴 들이밀며 넘어갔는데, 이래서 떨어진듯.
싱글턴의 특징
1) 클래스 내에 오직 단 한개의 instance만 갖도록 보장
2) 전역 접근 가능
// C++의 싱글턴 - 포인터 사용
class FileSystem
{
public:
static FileSystem* instance()
{
if (instance_ == NULL) instance_ = new FileSystem();
return *instance_;
}
private:
FileSystem() {}
~FileSystem() {}
static FileSystem* instance_;
};
// ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
// C++의 싱글턴 - 참조자 사용
class FileSystem
{
public:
static FileSystem& instance()
{
static FileSystem instance_;
return instance_;
}
private:
FileSystem() {}
~FileSystem() {}
};
// ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
// C#의 싱글턴
public class FileSystem
{
private static FileSystem instance = null;
public FileSystem GetInstance()
{
if(instance == null)
instance = this;
return instnace;
}
}
*Lazy initialize(지연 초기화) : 실제 인스턴스가 사용되는 시점에 인스턴스 초기화
-> 장점 : 필요할 때 인스터스를 생성해 메모리 누수 방지
-> 단점 : 멀티 스레드 환경에서 동시에 호출될 경우 인스턴스가 다중 생성될 여지 존재
*Eager initialize(이른 초기화) : 싱글턴 클래스가 생성될 때 인스턴스 초기화
-> 장점 : Thread-safe하게 인스턴스 생성
-> 단점 : 생성된 인스턴스가 계속 메모리 차지
C++에서 전역 객체(static, extern)는 프로그램이 실행될 때 초기화 된다.
-> static : 파일 단위 전역 변수
-> extern : 프로젝트 단위 전역 변수
전역 객체는 다음과 같이 5개의 유형으로 구분됨
(1) 전역객체
(2) namespace 유효범위에서 정의된 객체
(3) 파일 유효범위에서 static으로 정의된 객체
(4) 클래스 안 static 객체
(5) 함수 안 static 객체.
이중 4, 5번은 지역 전역 객체, 나머지는 비지역 전역 객체로 구분함.
-> 지역 전역 객체끼리만 선언 순서에 의한 초기화 순서가 보장됨.
즉 초기화 순서를 알 수 없기에 이른 초기화로 싱글턴을 사용할 경우 초기화되지 않은 전역 변수에 접근할 가능성이 있어 지연 초기화로 싱글턴을 사용하는 것을 권장함.
*C#의 static
1) 클래스 멤버로서의 static 키워드만 허용되고, 해당 타입(클래스, 변수, 메서드)에 접근할 때 초기화됨.
2) 전역 변수 대신 (전역) 필드라는 단어를 사용함.
// Effecttive C++에서 추천하는 싱글턴 구현 방식
class Singleton
{
};
Singleton* GetInstance()
{
static Singleton instance;
return &instance;
}
C++에서는 함수 호출을 통한 전역 객체의 초기화를 허용한다.
또한, 전역 객체의 초기화를 위해 호출된 함수는 main 이전에 호출된다.
즉, 아래와 같은 코드의 경우 main보다 Init이 먼저 실행됨.
TestClass Init()
{
...
return inst;
}
static TestClass instance = Init();
int main()
{
...
}
항상 그렇지만 단순하게 기본 문법책에서 소개하는 여러 명제들 뒤에는 꽤 깊은 cs가 숨어있다.
이 포스팅에서 소개한, 전역 변수의 초기화 순서를 보장하는지에 대한 여부, 정확히는 그 상세한 이유에 대해 찾는데 1주일이나 걸렸다.
해결하는 것은 의외로 쉬웠는데, C# 관련된 저서를 작성하신 분의 홈페이지에 질의응답을 통해서였다.
도움을 받은 만큼, 그 분의 홈페이지를 소개한다.
J & J - 정성태의 닷넷 이야기: Digital Stories
www.sysnet.pe.kr