Singleton에 대해서 질문이 있습니다.

gugudan의 이미지

template <typename T>
class Singleton
{
private:
    static T * selfInstance;
public:
    static T * getInstance()
    {
        if( selfInstance == NULL )
        {
            selfInstance = new T();
            selfInstance->initialize();
        }
		
        return selfInstance;
    }
    static void releaseInstance()
    { 
        if( selfInstance!= NULL )
            delete selfInstance;
		
        selfInstance = NULL;
    }
    virtual void initialize()=0;
};  



//class Test  : public Singleton<Test>
class Test  //: public Singleton<Test>
{
public:
    int aaa;
    Test() { aaa = 1; }
    virtual void initialize()
    {
        return ;
    }
    void test1()
    {
        printf("aaa : %d....\n",aaa++);
    }
	
};

Test* Singleton<Test>::selfInstance;

int main()
{
    //Test::getInstance()->test1();
    Singleton<Test>::getInstance()->test1();
    Singleton<Test>::getInstance()->test1();
    Singleton<Test>::getInstance()->test1();
    Singleton<Test>::getInstance()->test1();
    Singleton<Test>::getInstance()->test1();
    Singleton<Test>::getInstance()->test1();
    Singleton<Test>::releaseInstance();
	
    return 1;
}

위의 코드를 보면..
SIngleton을 상속받아서 사용해도
그렇치 않아도 결과는 똑같은거 같더군요..
꼭 상속을 받아야만 하는지요?

myueho의 이미지

상속받으면

Test::getInstance(); 와 같이 사용할 수 있습니다.

doldori의 이미지

gugudan wrote:
위의 코드를 보면..
SIngleton을 상속받아서 사용해도
그렇치 않아도 결과는 똑같은거 같더군요..
꼭 상속을 받아야만 하는지요?

Test 클래스의 목적에 따라 달라지겠죠.. Test가 Singleton 속성을 가져야 한다면
상속을 받을 것이고, 유일한 Test 개체를 원한다면 상속을 받는다는 건 이상하죠.
이 경우에는 후자 같은데요.
pool007의 이미지

singleton은 상속에는 별로 어울리지 않죠.
인스턴스를 마음대로 만들어버릴 가능성이 많아져서요.

상속을 하겠다면 monostate pattern을 써보세요.
http://c2.com/cgi/wiki?MonostatePattern

--
Passion is like genius; a miracle.

doldori의 이미지

pool007 wrote:
singleton은 상속에는 별로 어울리지 않죠.
인스턴스를 마음대로 만들어버릴 가능성이 많아져서요.

보통 singleton을 구현할 때는 생성자와 대입연산자를 private이나 protected로
하지 않나요? 그러면 상속을 받는다고 해도 마음대로 만들지는 못할 텐데요.
pool007의 이미지

부모가 싱글톤임을 유지해주려면,
상속을 받을때, 자식 클래스가 또 싱글톤이어야하죠. 이 상태에서 만약
Parent 하나에 자식이 C1, C2, C3, C4가 있다면 모두가 각각 싱글톤
이어야하죠. 그래서 별로 좋다는 생각이 안들던데요..
상속받은 객체들이 모두 싱글톤을 구현하고 있는 모양이 맘에 안들어서요.

간단히 monostate 로 만들면 부모에 대한 데이터는 하나로 유지되고,
자식은 싱글톤이 아니어도 상관이 없어요.

--
Passion is like genius; a miracle.

doldori의 이미지

singleton이 좋다, 나쁘다는 얘기를 한 것이 아니라 부모 클래스의 생성자가
private일 때 자식 클래스의 인스턴스를 마음대로 만들 수 있는 방법이 있는지
궁금해서 드린 말씀이었습니다.

creativeidler의 이미지

부모 클래스의 생성자가 private라도 자식 생성자에서 마음대로 생성자를 재정의해버리면 상관 없이 생성할 수 있죠. 그래서 싱글턴을 상속 받은 클래스는 부모클래스가 싱글턴이라도 똑같이 자기 자신도 싱글턴으로 해줘야 의미가 있습니다. 그래서 사실 싱글턴은 인스턴스의 유일성을 보장하기에 반드시 좋은 방법이라고는 할 수 없습니다.

하지만, 사실 싱글턴이라는 패턴을 처음 만들기 시작한 것은 상속이 가능하다는 점이 영향을 많이 미쳤죠. 사실 싱글턴의 요구사항들은 static 멤버만 가진 클래스를 만들어도 다 구현할 수 있습니다. 그럼에도 불구하고 굳이 싱글턴을 쓰는 것은 상속이 가능하기 때문이라고도 할 수 있죠.

어찌되었건 싱글턴 패턴은 상속을 사용하게 되면 문제가 생길 수 있습니다.

doldori의 이미지

저는 OP께서 보이신 코드가 C++이라서 계속 C++을 생각했는데, pool007님이나
creativeidler님께서는 혹시 자바 같은 다른 언어를 생각하시는 게 아닌가 하는
생각이 드는군요. (저는 자바를 전혀 모릅니다.)
다음은 C++로 싱글턴을 구현할 때 전형적인 코드입니다.

class Singleton 
{
public:
    static Singleton* Instance();
private:
    Singleton();
    Singleton(const Singleton&);
    static Singleton* pinstance;
};

// assume a class inherits Singleton
class Derived : public Singleton
{
public:
    Derived();   // does this ctor work?
    Derived(const Derived&);  // ditto
};

Derived에서 생성자를 public으로 했다고 하더라도 Singleton 클래스의 생성자까지
자동으로 public이 되는 것은 아닙니다. 이런 식으로 부모 클래스의 접근 권한을
마음대로 바꾸는 것이 가능하다면 접근 권한 자체가 의미없는 것이 되겠죠. 따라서
Derived()는 Singleton()을, Derived의 복사생성자는 Singleton의 복사생성자를
호출할 수 있는 방법이 없습니다. 이것이 자식 클래스의 인스턴스를 마음대로 만들
수 있다는 말씀에 의문을 느낀 이유입니다.
다른 언어에서는 이런 것이 가능한가요? 가능하다면 클래스를 설계하는 프로그래머의
의도가 무시될 수 있다는 점에서 문제가 있다는 것이 개인적인 생각입니다만.

ps. 자식 클래스에서도 싱글턴을 유지해야 하는 것이 좋은가 하는 점은 논외로 하면
좋겠습니다.

creativeidler의 이미지

그렇군요. 제가 착각했네요. C++에서는 어차피 불가능한 것이죠.
자바에서는 가능합니다.

어느 것이 옳은가는 잘은 모르겠습니다. 분명 클래스 설계자의 의도를 벗어나지 않게 한다는 점은 C++이 좋지만 C++도 생성자만 안될 뿐 일반 메쏘드는 private을 public으로 오버라이딩하는 것이 가능한데 생성자만 특별대우 하는 게 좋은지는 약간 의문입니다.

아뭏든 이렇게 보면 doldori님 말씀처럼 의도에 따라 Singleton을 상속하는 것이 좋을 수도 있고 아닐 수도 있겠네요. 대개의 경우는 Singleton을 상속하는 것이 편리하겠군요.

doldori의 이미지

저도 이제 의문이 풀렸습니다. :)

creativeidler wrote:
C++도 생성자만 안될 뿐 일반 메쏘드는 private을 public으로 오버라이딩하는 것이 가능한데 생성자만 특별대우 하는 게 좋은지는 약간 의문입니다.

이 점에 대해서는 다음의 글이 어느 정도 해답을 주지 않을까 합니다. kldp의
musiphil님께서 소개해주신 글인데, 너무나 멋진 글이라고 느껴져서 생각날 때마다
다시 읽어보고 있습니다.

"As with spoken languages, there is more to knowing the C++ language
than just knowing the grammar and the rules. You must know the idioms."
- Jim Hyslop & Herb Sutter, "Conversations: Virtually Yours"

http://www.cuj.com/documents/s=8000/cujcexp1812hyslop/

atie의 이미지

creativeidler wrote:
그렇군요. 제가 착각했네요. C++에서는 어차피 불가능한 것이죠.
자바에서는 가능합니다.

어느 것이 옳은가는 잘은 모르겠습니다. 분명 클래스 설계자의 의도를 벗어나지 않게 한다는 점은 C++이 좋지만 C++도 생성자만 안될 뿐 일반 메쏘드는 private을 public으로 오버라이딩하는 것이 가능한데 생성자만 특별대우 하는 게 좋은지는 약간 의문입니다.

아뭏든 이렇게 보면 doldori님 말씀처럼 의도에 따라 Singleton을 상속하는 것이 좋을 수도 있고 아닐 수도 있겠네요. 대개의 경우는 Singleton을 상속하는 것이 편리하겠군요.


주제와는 벗어날 수 있지만, 태클 하나 걸겠습니다. 자바에서 어느 경우에 싱글턴을 상속하는 것이 편리합니까? 대개의 경우라 하였는데 의문이 생겨서요.

메쏘드가 몇은 정의되고 몇은 그렇지 않은 경우, 싱글턴 추상 클래스를 명확히 하는 경우 그 추상 클래스를 상속을 받아 서브 클래스에서 메쏘드를 정의하여 사용하는 경우는 있다고 하더라도 서브 클래스는 반드시 싱클턴으로 해야 하고 하나의 오브젝트를 사용하기 위해서는 외부 패키지에서는 추상클래스에 있는 인스턴스를 반환하는 메쏘드를 콜하는 방법을 사용해야 하는데(리플렉션)... 이렇게 되면, 대개의 경우는 싱클턴을 상속을 하지 않는다가 보다 정확한 답변이 아닐까요.

상속을 하는 것이 가능하다고 하더라도 싱클턴은 상속을 하지 않는다 관례상(또는 일반적인) 올바른 것 같아서 드리는 질문입니다.

----
I paint objects as I think them, not as I see them.
atie's minipage

pok의 이미지

예전 글인데, 관련글이라 같이 적습니다.

C++에서도 상속이 필요하나요?
부모를 제한함으로써 자식은 생성제한에는 영향을 받지만, 그뿐이지 어차피 레퍼런스 카운팅은 자식들이 각자 해주어야 하지 않나요?

부모클래스에서 static으로 초기화하고 이것을 부모가 관리한다면, 이것이 한 자식의 여러 인스턴스가 생성되면서 동시에 생성되는 부모의 레퍼런스가 늘어나는 것인지 아니면 하니면 여러자식이 생성되면서 부모의 레퍼런스가 늘어나는지 알수 있는 방법이 없으니까 각각의 자식 객체가 각각의 레퍼런스를 갖게 되고 그렇다면 상속으로 얻을 수 있는 이점은 거의 없다고 봅니다.

목표가 싱글톤이라면 생성자를 숨기느냐 마느냐가 중요한게 아니라 인스턴스가 1개라는게 중요한거고, 그렇다면 굳이 상속이 필요없을것 같네요..

디자인패턴식의 싱글톤 구현에서는 스택에는 객체를 생성할 수 없고, MEC++ 에서의 구현에서는 힙에 객체를 생성할수 없으니, 차라리 그냥 객체에 static변수를 두고 이것을 생성자에서 카운팅하는게 가장 낫지 않을까 생각합니다.

pok의 이미지

으아. 다시생각해보니 부모가 아닌 자식의 생성자가 private라면 static 멤버함수만을 이용해서 생성해야하는데, 그러면 역시 힙에만 생성되는 결과가 되는군요.
아니면 휘발성이 아닌 static 변수의 참조를 리턴하는 MEC++의 재탕이 되거나요.

부모생성자를 protected에 두고 자식의 생성자에서 카운팅을 하면 일단 제가 원하는 제한된 생성을 하라~를 완수할 수 있겠지만, 이렇게하면 동일한 인터페이스를 통한 접근이라는 또다른 싱글톤의 장점을 누릴수 없게 되구요.

아.. 진정 싱글톤은 악마인것 같습니다. 적어도 C++에서는요.

...결론은 c++에서의 싱글톤에서는 상속이 유용할 수도 있다.. 군요.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.