C ++ 싱글 톤 디자인 패턴


735

최근에 저는 C ++에 대한 싱글 톤 디자인 패턴의 구현 / 구현에 부딪 쳤습니다. 다음과 같이 보입니다 (실제 예제에서 채택했습니다).

// a lot of methods are omitted here
class Singleton
{
   public:
       static Singleton* getInstance( );
       ~Singleton( );
   private:
       Singleton( );
       static Singleton* instance;
};

이 선언에서 인스턴스 필드가 힙에서 시작된 것으로 추론 할 수 있습니다. 이는 메모리 할당이 있음을 의미합니다. 메모리가 정확히 할당 해제 될 때가 확실하지 않은 것은 무엇입니까? 아니면 버그와 메모리 누수가 있습니까? 구현에 문제가있는 것 같습니다.

내 주요 질문은 올바른 방법으로 구현하는 것입니다.



10
이 백서에서는 C ++의 스레드 안전성과 함께 싱글 톤을 구현하는 방법에 대해 자세히 설명합니다. aristeia.com/Papers/DDJ%5FJul%5FAug%5F2004%5Frevised.pdf

106
@sbi-시스 만이 절대 값을 다룹니다. 싱글 톤 없이도 대부분의 문제를 해결할 수 있습니까? 물론. 싱글 톤은 스스로 문제를 일으 킵니까? 예. 그러나, 나는 정직하게 말할 수 없다 그들이있는 거 나쁜 , 디자인 장단점을 고려하여 접근 방식의 미묘한 차이를 이해에 대한 모든 때문이다.
derekerdmann

11
@derekerdmann : 나는 당신이 전역 변수를 필요가 없습니다 (당신이 하나를 필요로 할 때, 싱글 톤은 말하지 않았다 때로는 더 낫다). 내가 말한 것은 가능한 한 적게 사용해야한다는 것입니다. 귀중한 디자인 패턴으로 Singleton을 영광스럽게 만드는 것은 해킹 이므로 코드를 이해하기 어렵고 유지하기가 어렵고 테스트하기가 어렵다는 것보다는 사용하는 것이 좋습니다 . 이것이 내가 의견을 게시 한 이유입니다. 지금까지 말씀하신 내용 중 어느 것도 이것과 모순되지 않았습니다.
sbi

13
@ sbi : 당신이 말한 것은 "사용하지 마십시오." "가능한 한 적게 사용되어야한다"는 것이 훨씬 합리적이지는 않지만 나중에 다음과 같이 바꿨습니다.
jwd

답변:


1106

2008 년에 나는 기술적으로 스레드 안전하지 않은 게으른 평가되고, 파괴가 보장되고 파괴되지 않는 Singleton 디자인 패턴의 C ++ 98 구현을
제공했다.

다음은 게으른 평가, 올바르게 파괴되고 스레드로부터 안전한 Singleton 디자인 패턴의 업데이트 된 C ++ 11 구현입니다 .

class S
{
    public:
        static S& getInstance()
        {
            static S    instance; // Guaranteed to be destroyed.
                                  // Instantiated on first use.
            return instance;
        }
    private:
        S() {}                    // Constructor? (the {} brackets) are needed here.

        // C++ 03
        // ========
        // Don't forget to declare these two. You want to make sure they
        // are unacceptable otherwise you may accidentally get copies of
        // your singleton appearing.
        S(S const&);              // Don't Implement
        void operator=(S const&); // Don't implement

        // C++ 11
        // =======
        // We can use the better technique of deleting the methods
        // we don't want.
    public:
        S(S const&)               = delete;
        void operator=(S const&)  = delete;

        // Note: Scott Meyers mentions in his Effective Modern
        //       C++ book, that deleted functions should generally
        //       be public as it results in better error messages
        //       due to the compilers behavior to check accessibility
        //       before deleted status
};

싱글 톤 사용시기에 대한이 기사를 참조하십시오
.

초기화 순서 및 처리 방법에 대한이 두 기사를 참조하십시오.
정적 변수 초기화 순서
C ++ 정적 초기화 순서 문제 찾기

수명을 설명하는이 기사를 참조하십시오
. C ++ 함수에서 정적 변수의 수명은 얼마입니까?

싱글 톤에 대한 스레딩 영향에 대해 설명하는이 기사를 참조하십시오.
GetInstance 메소드의 정적 변수로 선언 된 싱글 톤 인스턴스는 스레드로부터 안전합니까?

C ++에서 이중 검사 잠금이 작동하지 않는 이유를 설명하는이 기사를 참조하십시오
. C ++ 프로그래머가 알아야 할 일반적인 정의되지 않은 동작은 무엇입니까?
Dr Dobbs : C ++ 및 이중 검사 잠금 위험 : 1 부


23
좋은 대답입니다. 그러나 이것은 스레드로부터 안전하지 않습니다. stackoverflow.com/questions/1661529/…
Varuna

4
@zourtney : 많은 사람들이 당신이 방금 한 일을 깨닫지 못합니다 :)
Johann Gerell

4
@MaximYegorushkin : 이것이 파괴 될 때 매우 잘 정의되어 있습니다 (모호성이 없습니다). 참조 : stackoverflow.com/questions/246564/...
마틴 뉴욕

3
What irks me most though is the run-time check of the hidden boolean in getInstance()이것이 구현 기술에 대한 가정입니다. 살아 있다는 가정은 필요 없습니다. stackoverflow.com/a/335746/14065를 참조하십시오 . 상황이 항상 유지되도록 강제 할 수 있습니다 (보다 적은 오버 헤드 Schwarz counter). 전역 변수는 순서를 강제하지 않기 때문에 컴파일 단위에서 초기화 순서와 관련하여 더 많은 문제가 있습니다. 이 모델의 장점은 1) 게으른 초기화입니다. 2) 명령을 집행하는 능력 (Schwarz가 도움을 주지만 더 추악합니다). 네는 get_instance()훨씬 더 추악한입니다.
Martin York

3
@kol : 아니요. 평소와 다릅니다. 초보자가 생각없이 코드를 복사하여 붙여 넣는다 고해서 일반적인 코드는 아닙니다. 항상 유스 케이스를보고 할당 연산자가 예상 한대로 수행하는지 확인해야합니다. 코드를 복사하여 붙여 넣으면 오류가 발생합니다.
Martin York

47

싱글 톤이기 때문에 일반적으로 파괴하기를 원하지 않습니다.

프로그램이 종료되면 단절되고 할당이 해제되며 이는 싱글 톤에 대한 정상적인 동작입니다. 명시 적으로 정리하고 싶다면 클래스에 정적 메소드를 추가하여 깨끗한 상태로 복원하고 다음에 사용할 때 다시 할당 할 수는 있지만 그 범위를 벗어납니다. "클래식"싱글 톤.


4
정적 Singleton * 인스턴스에서 delete가 명시 적으로 호출되지 않으면 여전히 기술적으로 메모리 누수로 간주되지 않습니까?
Andrew Garrison

7
더 이상 전역 변수를 선언하는 것만으로는 메모리 누수가 아닙니다.
ilya n.

15
무언가를 똑바로 세우려면 ... "메모리 누수"문제는 싱글 톤과 완전히 관련이 없습니다. 해체 순서가 중요한 상태 저장 리소스가있는 경우 싱글 톤은 위험 할 수 있습니다. 그러나 모든 메모리는 프로그램 종료시 운영 체제에 의해 완전히 회복됩니다. 99.9 %의 사례에서이 학문적 포인트를 무효화합니다. "메모리 누수"가 무엇인지 아닌지에 대해 문법을 앞뒤로 논의하고 싶다면 괜찮지 만 실제 디자인 결정에 방해가되지는 않습니다.
jkerian 2016 년

12
@jkerian : C ++ 컨텍스트에서 메모리 누수와 파괴는 실제로 메모리 누수에 관한 것이 아닙니다. 실제로 리소스 제어에 관한 것입니다. 메모리가 누출되면 디스트 로커가 호출되지 않으므로 객체와 관련된 모든 리소스가 올바르게 해제되지 않습니다. 메모리는 프로그래밍을 가르 칠 때 사용하는 간단한 예일 뿐이지 만 훨씬 더 복잡한 리소스가 있습니다.
Martin York

7
@Martin 나는 당신에게 완전히 동의합니다. 유일한 리소스가 메모리 인 경우에도 "중요하지 않은"누수 목록을 필터링하여 누수 목록을 살펴보아야하는 경우 프로그램에서 REAL 누수를 찾는 데 여전히 어려움을 겪게됩니다. 누출을보고하는 모든 도구가 문제가되는 것만보고하도록 이러한 모든 것을 정리하는 것이 좋습니다.
Dolphin

38

메모리 할당을 피할 수 있습니다. 멀티 스레딩 환경의 경우 문제가있는 많은 변형이 있습니다.

나는 이런 종류의 구현을 선호한다. (실제로, 싱글 톤을 가능한 많이 피하기 때문에 내가 선호한다고 올바르게 말하지는 않는다) :

class Singleton
{
private:
   Singleton();

public:
   static Singleton& instance()
   {
      static Singleton INSTANCE;
      return INSTANCE;
   }
};

동적 메모리 할당이 없습니다.


3
경우에 따라이 게으른 초기화는 이상적인 패턴이 아닙니다. 싱글 톤의 생성자가 힙에서 메모리를 할당하고 예를 들어 임베디드 시스템 또는 기타 엄격하게 제어되는 환경에서 해당 할당을 예측할 수있게하려는 경우를 예로들 수 있습니다. Singleton 패턴이 사용하기 가장 좋은 패턴 일 때 인스턴스를 클래스의 정적 멤버로 만드는 것을 선호합니다.
dma

3
더 큰 프로그램, 특히 동적 라이브러리가있는 프로그램의 경우. 기본이 아닌 모든 전역 또는 정적 객체는 라이브러리 언로드시 파괴 문제로 인해 많은 플랫폼에서 프로그램 종료시 segfaults / crashes를 유발할 수 있습니다. 이것이 Google을 포함한 많은 코딩 규칙이 사소한 정적 및 전역 객체의 사용을 금지하는 이유 중 하나입니다.
obecalp 2016 년

이러한 구현의 정적 인스턴스에는 내부 연결이 있으며 다른 변환 단위에 고유하고 독립적 인 사본이 있으므로 혼란스럽고 잘못된 동작이 발생합니다. 그러나 나는 그런 많은 구현을 보았습니다.
FaceBro

씬 뒤의 컴파일러가 자체 복사 생성자를 사용하는 여러 객체에 이것을 할당하지 못하게하는 것은 무엇입니까?
Tony Tannous

19

@Loki Astari의 대답 은 훌륭합니다.

그러나 여러 정적 개체가있는 경우에는 싱글 톤 을 사용하는 모든 정적 개체가 더 이상 필요하지 않을 때까지 싱글 톤손상 되지 않도록 보장 해야합니다.

이 경우 정적 소멸자가 프로그램 끝에서 호출되는 경우에도 모든 사용자에게 싱글 톤std::shared_ptr 을 유지하는 데 사용할 수 있습니다 .

class Singleton
{
public:
    Singleton(Singleton const&) = delete;
    Singleton& operator=(Singleton const&) = delete;

    static std::shared_ptr<Singleton> instance()
    {
        static std::shared_ptr<Singleton> s{new Singleton};
        return s;
    }

private:
    Singleton() {}
};

9

또 다른 비 할당 대안 : C필요한 경우 class 와 같이 싱글 톤을 만듭니다 .

singleton<C>()

사용

template <class X>
X& singleton()
{
    static X x;
    return x;
}

이것과 Cătălin의 대답은 현재 C ++에서 자동으로 스레드 안전하지 않지만 C ++ 0x에 있습니다.


현재 gcc에서는 스레드 안전합니다 (그리고 오랫동안 사용되었습니다).
Martin York

13
이 디자인의 문제점은 여러 라이브러리에서 사용되는 경우입니다. 각 라이브러리에는 해당 라이브러리가 사용하는 싱글 톤의 자체 사본이 있습니다. 따라서 더 이상 싱글 톤이 아닙니다.
Martin York

6

답변 중 CRTP 구현을 찾지 못 했으므로 여기에 있습니다.

template<typename HeirT>
class Singleton
{
public:
    Singleton() = delete;

    Singleton(const Singleton &) = delete;

    Singleton &operator=(const Singleton &) = delete;

    static HeirT &instance()
    {
        static HeirT instance;
        return instance;
    }
};

사용하려면 다음과 같이 클래스를 상속하십시오. class Test : public Singleton<Test>


1
기본 생성자를 보호하고 '= default;'로 만들 때까지 C ++ 17에서 작동하지 못했습니다.
WFranczyk

6

허용 된 답변의 솔루션에는 상당한 단점이 main()있습니다. 컨트롤이 함수를 떠난 후 싱글 톤의 소멸자가 호출 됩니다. 일부 종속 객체가 내부에 할당되면 실제로 문제가 발생할 수 있습니다 main.

Qt 응용 프로그램에 Singleton을 도입하려고 할 때이 문제가 발생했습니다. 모든 설정 대화 상자가 싱글 톤이어야하고 위의 패턴을 채택하기로 결정했습니다. 불행히도 Qt의 메인 클래스 QApplicationmain함수의 스택에 할당되었으며 Qt는 사용 가능한 응용 프로그램 객체가 없을 때 대화 상자를 만들거나 파괴하는 것을 금지합니다.

그렇기 때문에 힙 할당 싱글 톤을 선호합니다. 나는 모든 싱글 톤에 대한 명시 init()적이고 term()메소드를 제공 하고 내부에서 호출합니다 main. 따라서 싱글 톤 생성 / 파괴 순서를 완전히 제어 할 수 있으며 누군가 호출했는지 여부에 관계없이 싱글 톤이 생성되도록 보장합니다 getInstance().


2
현재 받아 들여진 답변을 언급하고 있다면 첫 번째 진술이 잘못되었습니다. 모든 정적 저장 기간 개체가 소멸 될 때까지 소멸자가 호출되지 않습니다.
Martin York

5

다음은 쉬운 구현입니다.

#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은 싱글 톤 오브젝트의 메모리 위치이며 프로그램 기간 동안 동일하지만 프로그램이 실행될 때마다 다릅니다 (일반적으로!).

NB 나사산이 안전하지 않으므로 나사산 안전을 보장해야합니다.


5

객체를 힙으로 할당하려면 고유 포인터를 사용하지 않는 것이 좋습니다. 고유 한 포인터를 사용하므로 메모리도 할당 해제됩니다.

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);

3
C ++ 11에서 더 이상 사용되지 않습니다. 대신 unique_ptr을 권장합니다. cplusplus.com/reference/memory/auto_ptr cplusplus.com/reference/memory/unique_ptr
Andrew

2
스레드 안전하지 않습니다. 더 나은 만들 수 있습니다 m_s현지 static의를 getInstance()하고 테스트없이 즉시 초기화합니다.
Galik

2

실제로 힙에서 할당되었지만 소스가 없으면 알 방법이 없습니다.

일반적인 구현 (이맥스에서 이미 가지고있는 일부 코드에서 가져온)은 다음과 같습니다.

Singleton * Singleton::getInstance() {
    if (!instance) {
        instance = new Singleton();
    };
    return instance;
};

... 그리고 범위를 벗어난 프로그램에 의존하여 나중에 정리하십시오.

정리를 수동으로 수행해야하는 플랫폼에서 작업하는 경우 수동 정리 루틴을 추가했을 것입니다.

이 방법으로 수행하는 또 다른 문제는 스레드로부터 안전하지 않다는 것입니다. 멀티 스레드 환경에서 두 인스턴스는 새 인스턴스를 할당하기 전에 "if"를 통과 할 수 있습니다 (둘 다). 어쨌든 정리하기 위해 프로그램 종료에 의존하는 경우 여전히 큰 문제는 아닙니다.


인스턴스 변수가 클래스 인스턴스에 대한 포인터임을 알 수 있으므로 추론 할 수 있습니다.
Artem Barger

3
싱글 톤을 동적으로 할당 할 필요가 없습니다. 실제로 위의 디자인을 사용하여 자동으로 할당을 해제 할 수있는 방법이 없기 때문에 이것은 나쁜 생각입니다. 범위를 벗어나게하려면 소멸자를 호출하지 않고 게으른 것입니다.
Martin York

atexit 함수를 사용하여 자동 할당 해제 할 수 있습니다. 그것이 우리가하는 일입니다 (좋은 생각은 아닙니다)
Joe

2

사람이 언급 했 std::call_oncestd::once_flag? 이중 검사 잠금을 포함한 대부분의 다른 접근 방식이 중단되었습니다.

싱글 톤 패턴 구현에서 한 가지 주요 문제는 안전한 초기화입니다. 유일한 안전한 방법은 동기화 장벽으로 초기화 시퀀스를 지키는 것입니다. 그러나 이러한 장벽 자체는 안전하게 시작되어야합니다. std::once_flag안전한 초기화를 보장하는 메커니즘입니다.


2

우리는 최근에이 주제를 EECS 수업에서 다뤘습니다. 강의 노트를 자세히 보려면 http://umich.edu/~eecs381/lecture/IdiomsDesPattsCreational.pdf를 방문하십시오.

Singleton 클래스를 올바르게 만드는 두 가지 방법이 있습니다.

첫 번째 방법 :

예제에서와 비슷한 방식으로 구현하십시오. 파괴에 관해서는 "단일 프로그램은 일반적으로 프로그램 실행 기간 동안 견뎌야한다. 대부분의 OS는 프로그램이 종료 될 때 메모리와 대부분의 다른 자원을 복구하므로 이에 대해 걱정하지 않아도된다"고 말했다.

그러나 프로그램 종료시 정리하는 것이 좋습니다. 따라서 보조 정적 SingletonDestructor 클래스를 사용하여이 작업을 수행하고이를 Singleton의 친구로 선언 할 수 있습니다.

class Singleton {
public:
  static Singleton* get_instance();

  // disable copy/move -- this is a Singleton
  Singleton(const Singleton&) = delete;
  Singleton(Singleton&&) = delete;
  Singleton& operator=(const Singleton&) = delete;
  Singleton& operator=(Singleton&&) = delete;

  friend class Singleton_destroyer;

private:
  Singleton();  // no one else can create one
  ~Singleton(); // prevent accidental deletion

  static Singleton* ptr;
};

// auxiliary static object for destroying the memory of Singleton
class Singleton_destroyer {
public:
  ~Singleton_destroyer { delete Singleton::ptr; }
};

Singleton_destroyer는 프로그램 시작시 생성되고 "프로그램이 종료되면 모든 전역 / 정적 객체가 런타임 라이브러리 종료 코드 (링커에 의해 삽입 됨)에 의해 파괴되므로 _destroyer가 파괴됩니다. 소멸자는 Singleton을 삭제하여 실행됩니다. 파괴 장치."

두 번째 방법

이것을 C ++ 마법사 Scott Meyers가 만든 Meyers Singleton이라고합니다. get_instance ()를 다르게 정의하십시오. 이제 포인터 멤버 변수를 제거 할 수도 있습니다.

// public member function
static Singleton& Singleton::get_instance()
{
  static Singleton s;
  return s;
}

반환 된 값은 참조 용이므로 멤버 변수에 액세스하는 .대신 구문을 사용할 수 있으므로 깔끔 ->합니다.

"컴파일러는 선언을 통해 처음으로 's'를 작성하는 코드를 자동으로 빌드 한 다음 프로그램 종료시 정적 오브젝트를 삭제합니다."

Meyers Singleton을 사용하면 "종료 시점에 객체가 서로 의존하는 경우 매우 어려운 상황에 처할 수 있습니다. Singleton은 언제 다른 객체에 비해 사라 집니까? 그러나 간단한 응용 프로그램의 경우에는 잘 작동합니다."


1

여기에있는 다른 토론 외에도 사용을 하나의 인스턴스로 제한하지 않고 전역 성을 가질 수 있다는 점에 주목할 가치가 있습니다. 예를 들어, 참조 카운트의 경우를 생각해보십시오.

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); 

Store참조는 컴파일 타임에 정보가 제공되므로 해당 포인터를 다시 저장할 필요가 없습니다 . 또한 Store컴파일러가 전역을 요구하기 때문에의 수명 에 대해 걱정할 필요가 없습니다 . 실제로 하나의 인스턴스 만 Store있는 경우이 방법에는 오버 헤드가 없습니다. 둘 이상의 인스턴스를 사용하면 코드 생성에 대해 영리한 것은 컴파일러의 책임입니다. 필요한 경우, ItemRef클래스도 할 수 friendStore(당신이 템플릿 가질 수 친구를!).

경우 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>. */ };

사용자는 이제 StoreWrapper각 글로벌 Store인스턴스에 대한 유형 (및 글로벌 인스턴스)을 작성 하고 항상 랩퍼 인스턴스를 통해 상점에 액세스 할 수 있습니다 (따라서를 사용하는 데 필요한 템플리트 매개 변수의 세부 사항을 잊어 버림 Store).


0

이것은 개체 수명 관리에 관한 것입니다. 소프트웨어에 싱글 톤 이상이 있다고 가정합니다. 그리고 그들은 Logger singleton에 의존합니다. 응용 프로그램을 제거하는 동안 다른 싱글 톤 개체가 로거를 사용하여 제거 단계를 기록한다고 가정합니다. 로거를 마지막으로 정리해야합니다. 따라서이 백서를 확인하십시오 : http://www.cs.wustl.edu/~schmidt/PDF/ObjMan.pdf


0

내 구현은 Galik과 유사합니다. 차이점은 응용 프로그램이 종료되고 정적 포인터가 정리 될 때까지 메모리를 유지하는 대신 공유 포인터가 할당 된 메모리를 정리하는 것입니다.

#pragma once

#include <memory>

template<typename T>
class Singleton
{
private:
  static std::weak_ptr<T> _singleton;
public:
  static std::shared_ptr<T> singleton()
  {
    std::shared_ptr<T> singleton = _singleton.lock();
    if (!singleton) 
    {
      singleton.reset(new T());
      _singleton = singleton;
    }

    return singleton;
  }
};

template<typename T>
std::weak_ptr<T> Singleton<T>::_singleton;

0

클래스 외부에서 인스턴스 포인터를 선언하지 않은 것을 제외하고는 코드가 정확 합니다 . 정적 변수의 내부 클래스 선언은 C ++의 선언으로 간주되지 않지만 C # 또는 Java 와 같은 다른 언어에서는 허용됩니다 .

class Singleton
{
   public:
       static Singleton* getInstance( );
   private:
       Singleton( );
       static Singleton* instance;
};
Singleton* Singleton::instance; //we need to declare outside because static variables are global

Singleton 인스턴스 를 수동으로 삭제할 필요가 없다는 것을 알아야합니다 . 전체 프로그램에서 단일 객체가 필요하므로 프로그램 실행이 끝나면 자동으로 할당이 해제됩니다.


-1

위에 링크 된 논문은 이중 확인 잠금의 단점에 대해 설명합니다. 컴파일러는 객체의 생성자가 호출되기 전에 객체에 메모리를 할당하고 할당 된 메모리의 주소에 대한 포인터를 설정할 수 있다는 것입니다. 그러나 C ++에서는 할당자를 사용하여 메모리를 수동으로 할당 한 다음 구성 호출을 사용하여 메모리를 초기화하는 것이 매우 쉽습니다. 이 접근법을 사용하면 이중 검사 잠금이 제대로 작동합니다.


2
불행히도. 이것은 최고의 C ++ 개발자들에 의해 심도있게 논의되었습니다. C ++ 03에서 이중 검사 잠금이 해제되었습니다.
Martin York

-1
#define INS(c) private:void operator=(c const&){};public:static c& I(){static c _instance;return _instance;}

예:

   class CCtrl
    {
    private:
        CCtrl(void);
        virtual ~CCtrl(void);

    public:
        INS(CCtrl);

-1

간단한 싱글 톤 클래스, 헤더 클래스 파일이어야합니다

#ifndef SC_SINGLETON_CLASS_H
#define SC_SINGLETON_CLASS_H

class SingletonClass
{
    public:
        static SingletonClass* Instance()
        {
           static SingletonClass* instance = new SingletonClass();
           return instance;
        }

        void Relocate(int X, int Y, int Z);

    private:
        SingletonClass();
        ~SingletonClass();
};

#define sSingletonClass SingletonClass::Instance()

#endif

다음과 같이 싱글 톤에 액세스하십시오.

sSingletonClass->Relocate(1, 2, 5);

-3

정적 객체가 삭제되는 정적 함수를 작성해야한다고 생각합니다. 응용 프로그램을 닫으려고 할 때이 함수를 호출해야합니다. 이렇게하면 메모리 누수가 발생하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.