아래와 같이 작성하면 간단하게 Thread-safe한 Singleton이 구현된다.
class Singleton
{
public:
static Singleton& getInstance()
{
static Singleton instance;
return instance;
}
};
이게 가능한 이유는 C+11의 아래 규칙 때문이다.
C++11에서 정적 지역변수의 초기화는 멀티스레드 환경에서도 한 번만 수행됨이 보장된다.
원문은 이렇다.
If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.
물론 클래스의 생성자 내에서 또 다른 복잡한 동기화가 필요하거나 언어 표준을 확실하게 지원하지 않는 환경에서는 부가적인 동기화 코드들을 추가하여야 한다.
위의 코드는 동기화 문제에 대한 부분만이므로 "컴파일러가 자동으로 만들어 주는 함수들(Effective C++ 참고)"이나 상속에 대한 부분 까지 신경쓰면 아래와 같이 구성할 수 있다.
(이 때 move 생성자 및 move 할당 연산자는 소멸자나 복사 생성/할당 연산자 를 명시적으로 선언하면 자동 생성되지 않는다.)
class Singleton
{
public:
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton& getInstance()
{
static Singleton instance;
return instance;
}
void callFunction() {}
protected:
Singleton() {}
virtual ~Singleton() {}
};
위와 같이 만드는 singleton을 보통 Meyer’s Singleton
이라 부른다. effective 시리즈의 저자 이름인 scott meyers 에서 비롯된것으로 보인다.
간단한 Singleton을 구성할 때 템플릿 삼아 사용하면 유용하다.
하지만 구조적인 관점에서 전역 인스턴스처럼 쓰이는 Singleton은 되도록 사용하지 않는 것이 제일 좋은 것 같다. 편리함에는 반드시 따르는 위험이나 단점이 있기 마련이다.(ex. 단위테스트가 어려움)