B::~B()
으로 구성 마지막 이었기 때문에
C::~C()
는 oups, 그것은 C
의 인스턴스에 액세스하려고 ...라고!
우리는 따라서
3. 새로운 전략 여기
아이디어는 간단하다 ... 파괴, 험에서 정의되지 않은 동작이있다.
S& S::Instance() { if (MInstance == 0) MInstance = new S(); return *MInstance; }
가 사실 여부를 확인합니다 : 포인터가 당신이 전화를받을 것이다 작성한 코드의 전에 0
로 설정할 수 있도록 글로벌 내장 기능은 다른 전역하기 전에 초기화, 그것은 테스트가 보장 인스턴스가 정확하지 않습니다.
그러나 말한에서, 여기에 메모리 누수 및 호출되지 없구요 최악의 소멸자가있다. 솔루션이 존재하며 표준화되었습니다. atexit
함수에 대한 호출입니다.
atexit
기능을 사용하면 프로그램 종료 중에 실행할 작업을 지정할 수 있습니다. 즉, 우리는 싱글 확실히 작성할 수 있습니다
// in s.hpp
class S
{
public:
static S& Instance(); // already defined
private:
static void CleanUp();
S(); // later, because that's where the work takes place
~S() { /* anything ? */ }
// not copyable
S(S const&);
S& operator=(S const&);
static S* MInstance;
};
// in s.cpp
S* S::MInstance = 0;
S::S() { atexit(&CleanUp); }
S::CleanUp() { delete MInstance; MInstance = 0; } // Note the = 0 bit!!!
첫째,의는 atexit
에 대해 자세히 알아 보자. 서명은 int atexit(void (*function)(void));
입니다. 즉, 아무것도 인수를 취하지 않고 아무것도 반환하지 않는 함수에 대한 포인터를 받아들입니다.
둘째, 어떻게 작동합니까? 이전의 사용 사례와 똑같습니다. 초기화 할 때 함수 호출 포인터를 작성하고 호출 할 때마다 스택을 한 번에 하나씩 비 웁니다. 사실, 함수는 Last-In First-Out 방식으로 호출됩니다.
여기서 어떻게됩니까? 처음 액세스에
? 글쎄,이 경우에는 포인터를 0
으로 설정 했으므로 임시 싱글 톤을 다시 작성하고 사이클이 새로 시작됩니다. 내가 스택을 털어 놓고 있기 때문에 오래 살지 않을 것이다.
Alexandrescu는 화산재가 파괴 된 후 필요할 경우 재에서 부활 할 때 Phoenix Singleton
이라고 부릅니다.
또 다른 대안은 정적 플래그를 가지고 정리 중에 destroyed
으로 설정하고 사용자가 null 포인터를 반환하는 등의 싱글 톤 인스턴스를 얻지 못했다는 것을 사용자에게 알리는 것입니다. 내가 포인터를 반환 (또는 참조)을 가지고있는 유일한 문제는 거라고이다 더 나은 희망 아무도의 그것에 delete
를 호출 할만큼 멍청 : /는 모노 이드 패턴이
우리가 얘기하고 있기 때문에
(4) Singleton
나는 그것이 Monoid
패턴을 소개 할 때라고 생각한다. 본질적으로, 이것은 Flyweight
패턴의 퇴화 된 사례 또는 Proxy
의 사용을 Singleton
이상으로 볼 수 있습니다.
Monoid
패턴은 간단합니다. 클래스의 모든 인스턴스는 공통 상태를 공유합니다.
나는하지 피닉스 구현 : 혜택은 무엇입니까
class Monoid
{
public:
void foo() { if (State* i = Instance()) i->foo(); }
void bar() { if (State* i = Instance()) i->bar(); }
private:
struct State {};
static State* Instance();
static void CleanUp();
static bool MDestroyed;
static State* MInstance;
};
// .cpp
bool Monoid::MDestroyed = false;
State* Monoid::MInstance = 0;
State* Monoid::Instance()
{
if (!MDestroyed && !MInstance)
{
MInstance = new State();
atexit(&CleanUp);
}
return MInstance;
}
void Monoid::CleanUp()
{
delete MInstance;
MInstance = 0;
MDestroyed = true;
}
를 노출 할 수있는 기회를 걸릴거야? 상태가 공유된다는 사실을 숨기고 Singleton
을 숨 깁니다.
- 혹시이 개 서로 다른 상태를 가질해야하는 경우 (예를 들어
Factory
를 호출하여 Singleton
교체) 를 사용하는 모든 코드를 변경하지 않고 당신이 그것을을 것 가능성이 있습니다
- Nodoby가 당신의 싱글 톤 인스턴스에서
delete
으로 전화를 걸면, 실제로 상태를 관리하고 사고를 예방할 수 있습니다. 어쨌든 악의적 인 사용자에 대해서는 많은 것을 할 수 없습니다! 이 올바르게 처리 할 수 파괴 됐어요 후 경우가
5. 마지막 단어
(아무것도하지 않고 로그 등 ...)라고 있도록
Alexandrescu의 "Modern C++ Design"에는 싱글 튼을 안전하고 정확하게 만들려고 노력한 전체 장이 포함되어있어 많은 어둠의 모퉁이를 탐험하고 있습니다. 제 의견으로는 "그냥하지 마세요"라고 요약 할 수 있습니다. –
@Mike - 훌륭한 참고 자료이며 전적으로 동의합니다. –