개발 이론/GoF
[디자인 패턴] Modern C++ Singleton
로파이
2021. 4. 16. 22:07
모던 C++ 스타일 싱글턴 패턴을 템플릿으로 구현한다.
구현점
1. 멀티 스레드에 안전한, 전역적으로 딱 한번만 초기화하여 인스턴스가 유일함을 보장한다.
2. 템플리 클래스로 정의하고 GetInst()에서 구체 클래스의 생성자를 호출하므로 구체 클래스에서 싱글톤클래스를 friend로 선언해야한다.
3. unique_ptr의 삭제자 구조체를 선언하고 스마트포인터 인스턴스 생성시 이 호출가능한 구조체의 인스턴스를 넘겨준다.
- 템플릿 클래스에서 virtual 소멸자로 선언했기 때문에 구체 클래스에서 삭제할 멤버가 있다면 편하게 소멸자를 정의할 수 있다.
- 소멸자를 private로 선언해도 unique_ptr에서 private 소멸자를 찾을 수 없다는 에러를 없앨 수 있다.
#pragma once
#include <memory>
#include <mutex>
template<typename T>
class Singleton
{
public:
Singleton(const Singleton&) = delete;
Singleton(Singleton &&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton& operator=(Singleton&&) = delete;
private:
struct Deleter
{
void operator()(T* inst)
{
delete inst;
}
};
private:
static std::unique_ptr<T, Deleter> m_pInst;
static std::once_flag m_flag;
protected:
Singleton() = default;
virtual ~Singleton() = default;
public:
static std::unique_ptr<T, Deleter>& GetInst()
{
std::call_once(m_flag, []()
{
Singleton<T>::m_pInst.reset(new T);
char name[256] = { 0 };
sprintf_s(name, "%s instantiated\n", typeid(T).name());
OutputDebugString(name);
});
return m_pInst;
}
};
template<typename T>
std::unique_ptr<T, typename Singleton<T>::Deleter>
Singleton<T>::m_pInst = std::unique_ptr<T, typename Singleton<T>::Deleter>(nullptr, typename Singleton<T>::Deleter());
template<typename T>
std::once_flag Singleton<T>::m_flag;
구체 클래스 예시
- 게임 타이머 클래스를 싱글톤으로 선언할 경우 예시
class Timer : public Singleton<Timer>
{
friend class Singleton<Timer>;
private:
Timer();
private:
bool m_bStop = false;
HWND m_hWnd = nullptr;
chrono::steady_clock::time_point m_Last;
unsigned int m_FrameCount = 0;
float m_fDuration = 0.f;
float m_fStopDuration = 0.f;
public:
bool IsStopped() const { return m_bStop; }
bool Init(HWND hWnd);
void Stop();
void Go();
void Reset();
float Mark() noexcept;
float Peek() const noexcept;
};
참고: bitboom.github.io/singleton-with-cpp11