디자인 패턴/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