c++ 싱글톤 자바 - C ++ 싱글 톤 디자인 패턴
최근에 나는 C ++을위한 Singleton 디자인 패턴의 구현 / 구현에 부딪 혔습니다. 그것은 다음과 같이 보입니다 (저는 이것을 실제 사례에서 채택했습니다) :
// a lot of methods are omitted here
class Singleton
{
public:
static Singleton* getInstance( );
~Singleton( );
private:
Singleton( );
static Singleton* instance;
};
이 선언에서 인스턴스 필드가 힙에서 시작된다고 추론 할 수 있습니다. 이는 메모리 할당이 있음을 의미합니다. 나에게 완전히 불분명 한 점은 정확히 메모리가 할당 해제 될 때인 것인가? 아니면 버그와 메모리 누수가 있습니까? 구현에 문제가있는 것처럼 보입니다.
내 주요 질문은 올바른 방법으로 구현하는 것입니다.
할당하지 않은 또 다른 대안 : 필요에 따라 클래스 C
와 같은 싱글 톤을 만듭니다.
singleton<C>()
~을 사용하여
template <class X>
X& singleton()
{
static X x;
return x;
}
이것도 Cătălin의 대답은 자동으로 현재 C ++에서는 thread-safe가 아니지만 C ++ 0x에있게됩니다.
개체를 힙에 할당하려면 고유 한 포인터를 사용하지 않는 것이 좋습니다. 우리는 유일한 포인터를 사용하고 있기 때문에 메모리도 할당 해제됩니다.
class S
{
public:
static S& getInstance()
{
if( m_s.get() == 0 )
{
m_s.reset( new S() );
}
return *m_s;
}
private:
static std::unique_ptr<S> m_s;
S();
S(S const&); // Don't Implement
void operator=(S const&); // Don't implement
};
std::unique_ptr<S> S::m_s(0);
다음은 쉬운 구현입니다.
#include <Windows.h>
#include <iostream>
using namespace std;
class SingletonClass {
public:
static SingletonClass* getInstance() {
return (!m_instanceSingleton) ?
m_instanceSingleton = new SingletonClass :
m_instanceSingleton;
}
private:
// private constructor and destructor
SingletonClass() { cout << "SingletonClass instance created!\n"; }
~SingletonClass() {}
// private copy constructor and assignment operator
SingletonClass(const SingletonClass&);
SingletonClass& operator=(const SingletonClass&);
static SingletonClass *m_instanceSingleton;
};
SingletonClass* SingletonClass::m_instanceSingleton = nullptr;
int main(int argc, const char * argv[]) {
SingletonClass *singleton;
singleton = singleton->getInstance();
cout << singleton << endl;
// Another object gets the reference of the first object!
SingletonClass *anotherSingleton;
anotherSingleton = anotherSingleton->getInstance();
cout << anotherSingleton << endl;
Sleep(5000);
return 0;
}
하나의 오브젝트 만 작성되고 이후에 매번 오브젝트 참조가 리턴됩니다.
SingletonClass instance created!
00915CB8
00915CB8
여기서 00915CB8은 싱글 톤 Object의 메모리 위치이며, 프로그램이 실행되는 동안 동일하지만 (일반적으로!) 프로그램이 실행될 때마다 다릅니다.
NB 이것은 스레드로부터 안전하지 않습니다. 스레드 안전을 보장해야합니다.
이것은 객체 수명 관리에 관한 것입니다. 소프트웨어에 싱글 톤 이상을 가지고 있다고 가정합니다. 그리고 그들은 Logger 싱글 톤에 의존합니다. 응용 프로그램이 파괴되는 동안 또 다른 싱글 톤 객체가 Logger를 사용하여 파괴 단계를 기록한다고 가정합니다. 로거를 마지막으로 정리해야한다는 것을 보장해야합니다. 따라서이 백서를 확인하십시오. http://www.cs.wustl.edu/~schmidt/PDF/ObjMan.pdf
누구든지 std::call_once
및 std::once_flag
언급 std::once_flag
습니까? 이중 점검 잠금을 비롯한 대부분의 다른 접근 방식이 손상되었습니다.
싱글 톤 패턴 구현의 주요 문제점 중 하나는 안전한 초기화입니다. 유일하게 안전한 방법은 장벽을 동기화하여 초기화 시퀀스를 보호하는 것입니다. 그러나 이러한 장벽 자체는 안전하게 시작되어야합니다. std::once_flag
는 안전 초기화를 보장하는 메커니즘입니다.
여기 다른 토론 외에도 하나의 인스턴스에만 사용을 제한하지 않고 전역 성을 가질 수 있다는 점은 가치가 있습니다. 예를 들어 참조 계산의 경우를 생각해보십시오.
struct Store{
std::array<Something, 1024> data;
size_t get(size_t idx){ /* ... */ }
void incr_ref(size_t idx){ /* ... */}
void decr_ref(size_t idx){ /* ... */}
};
template<Store* store_p>
struct ItemRef{
size_t idx;
auto get(){ return store_p->get(idx); };
ItemRef() { store_p->incr_ref(idx); };
~ItemRef() { store_p->decr_ref(idx); };
};
Store store1_g;
Store store2_g; // we don't restrict the number of global Store instances
이제 어딘가에 main
과 같은 함수 내부에서 할 수 있습니다.
auto ref1_a = ItemRef<&store1_g>(101);
auto ref2_a = ItemRef<&store2_g>(201);
ref는 컴파일시에 정보가 제공되기 때문에 포인터를 각각의 Store
다시 저장할 필요가 없습니다. 컴파일러가 전역 적이어야하므로 Store
의 수명에 대해 걱정할 필요가 없습니다. Store
인스턴스가 실제로 단 하나라면이 방법에는 오버 헤드가 없습니다. 하나 이상의 인스턴스에서 컴파일러는 코드 생성에 대해 영리해야합니다. 필요한 경우 ItemRef
클래스를 Store
의 friend
로 만들 수도 있습니다 (템플릿이있는 친구도 가질 수 있습니다!).
Store
자체가 템플릿 기반 클래스 인 경우 작업이 복잡해 지지만 다음과 같은 서명으로 도우미 클래스를 구현하여이 메서드를 사용할 수도 있습니다.
template <typename Store_t, Store_t* store_p>
struct StoreWrapper{ /* stuff to access store_p, e.g. methods returning
instances of ItemRef<Store_t, store_p>. */ };
사용자는 이제 각 전역 Store
인스턴스에 대해 StoreWrapper
유형 (및 전역 인스턴스)을 만들 수 있으며 항상 래퍼 인스턴스를 통해 저장소에 액세스합니다. 따라서 Store
를 사용하기 위해 필요한 템플릿 매개 변수의 세부 정보를 잊어 버릴 수 있습니다.
정적 개체를 삭제해야하는 정적 함수를 작성해야한다고 생각합니다. 응용 프로그램을 닫을 때이 함수를 호출해야합니다. 이렇게하면 메모리 누출이 발생하지 않습니다.
다음과 같이 새 게재 위치를 사용하는 방법 :
class singleton
{
static singleton *s;
static unsigned char *buffer[sizeof(singleton)/4 *4] //4 byte align
static singleton* getinstance()
{
if (s == null)
{
s = new(buffer) singleton;
}
return s;
}
};