싱글톤(단일체) 구현에서 소멸처리가 제대로 안됩니다.

프로그래밍 일반에 관한 포럼입니다.

Moderator: 류광

Locked
비회원

싱글톤(단일체) 구현에서 소멸처리가 제대로 안됩니다.

Post by 비회원 »

GOF의 디자인 패턴을 공부하던 중 싱글톤 프로그램을 한번 만들어 봤습니다.
클래스를 책의 내용대로 작성하고 거기에서 추가로 소멸자에서 메모리를 자동해제 할 수 있게 작성해봤습니다.

Code: Select all


//단일체
class JSingleton
{
public:
	static JSingleton* Instance(void)
	{
		if(_instance == NULL)
		{
			FILE* fp = fopen("싱글톤 생성.txt", "w");
			fclose(fp);
			_instance = new JSingleton;
		}
		return _instance;
	}
	~JSingleton()
	{
		if(_instance != NULL)
		{
			FILE* fp = fopen("싱글톤 해제.txt", "w");
			fclose(fp);
			delete _instance;
		}
	}

	void Test(void)
	{
		printf("싱글톤 테스트\n", _instance, this);
	}

protected:
	JSingleton() {}

private:
	static JSingleton* _instance; // (== this)
};
JSingleton* JSingleton::_instance = NULL;




int _tmain(int argc, _TCHAR* argv[])
{
//	using std::auto_ptr;
//	auto_ptr<JSingleton> ps = JSingleton::Instance(); //정상적으로 해제 됨
	JSingleton* ps = JSingleton::Instance(); //소멸자 호출 안 됨
	ps->Test();

	return 0;
}
위와 같이 작성하고 실행해봤습니다.
그런데 소멸자가 호출이 되지 않네요.
JSingleton* ps을 로컬(메인 함수 내에서)로 선언하였으니 당연히 메인 함수가 끝날 때 소멸자가 실행이
될 것으로 예상했지만 안되더군요.
JSingleton::_instance 멤버가 static으로 되어있어서 그런 걸까요?
그래서 메인 함수의 끝나는 지점에

Code: Select all

delete ps;
라고 넣어봤는데 delete가 두번 실행되는 듯 합니다.(외부에서 한번, 소멸자에서 또 한번 실행 됨)
제가 의도한 것은 종료직전에 외부적인 호출 없이도 객체내에서 스스로 메모리가 해제되고
delete가 한번만 실행되는 겁니다.
auto_ptr을 사용하지 않고도 말이죠.
어떤 방법이 있을까요.
bklist
Posts: 17
Joined: 2008-04-18 12:59
Location: 나 강남에서 근무해!

동적 할당을 쓸 필요가 없죠.

Post by bklist »

Code: Select all

static JSingleton* Instance(void)
	   {
	   	   static JSingleton Instance;
                                   return &Instance;
	   }
이런식으로 해주시면 동적할당에 대한 해제도 걱정안해도 되고 편하죠.

Code: Select all

JSingleton* ps = JSingleton::Instance(); //소멸자 호출 안 됨
이부분이 문제인데 소스를 컴파일러 입장에서 풀어서 본다면

ps에는 new로 생성한 객체가 들어가게 되죠 이경우 당연히 delete를 해줘야 합니다.
하지만 소멸자에 보면 delete가 또 들어있겠죠 그러면?

소멸자 부분에서 계속적으로 소멸자를 재귀 호출하는 꼴이 됩니다.

결론은 위에처럼 객체 접근자에 정적으로 생성을 해놓으시면 소멸자에 아무런 행위를 안해도 됩니다.

이해가 안되시면 조금더 공부를..
충분한 명상과 체험은 구현의 첫걸음
http://bklist.egloos.com/
비회원

Post by 비회원 »

늦은 시각에 답변 주셔서 고맙습니다^^
말씀하신대로 굳이 클래스 멤버에다가 동적할당을 할 필요가 없는 것 같네요.
부끄러움에 몸둘바를 모르겠습니다^^;
비회원

개념은 가장 명확하지만 구현이 의외로 어렵습니다.

Post by 비회원 »

지금 스레드 여신분의 질문 의도를 해결 하려면

Smart Pointer 또는 stl 의 auto_ptr 을 한번 보시길 권해드립니다.


코드:
static JSingleton* Instance(void)
{
static JSingleton Instance;
return &Instance;
}


이런식으로 해주시면 동적할당에 대한 해제도 걱정안해도 되고 편하죠.

싱글턴에서 생성방식이 정적객체를 이용하였을때는 생성소멸의 우선순위 문제가 있습니다.

컴파일러마다 제각각 전역객체를 임의로 생성과 소멸을 하기때문에

객체간 생성소멸의 우선순위는 보장할수없습니다.

그런 이유로 자유영역(Heap)에 올리는 것입니다.


ps.
저는 c++을 9년가량 공부했지만 singleton 이 가장 구현하기 까다로웠습니다.
100% 그 규약을 맞추기가 쉽지않더군요.
이것은 아마도 oop를 적극적으로 cover하지 못하는 c++의 한계가 아닐까 생각합니다.
c#과 java 등 에서는 어떻게 구현했을런지 궁금하군요.
비회원

Re: 싱글톤(단일체) 구현에서 소멸처리가 제대로 안됩니다.

Post by 비회원 »

비회원 wrote:GOF의 디자인 패턴을 공부하던 중 싱글톤 프로그램을 한번 만들어 봤습니다.
클래스를 책의 내용대로 작성하고 거기에서 추가로 소멸자에서 메모리를 자동해제 할 수 있게 작성해봤습니다.

Code: Select all


//단일체
class JSingleton
{
public:
	static JSingleton* Instance(void)
	{
		if(_instance == NULL)
		{
			FILE* fp = fopen("싱글톤 생성.txt", "w");
			fclose(fp);
			_instance = new JSingleton;
		}
		return _instance;
	}
	~JSingleton()
	{
		if(_instance != NULL)
		{
			FILE* fp = fopen("싱글톤 해제.txt", "w");
			fclose(fp);
			delete _instance;
		}
	}

	void Test(void)
	{
		printf("싱글톤 테스트\n", _instance, this);
	}

protected:
	JSingleton() {}

private:
	static JSingleton* _instance; // (== this)
};
JSingleton* JSingleton::_instance = NULL;




int _tmain(int argc, _TCHAR* argv[])
{
//	using std::auto_ptr;
//	auto_ptr<JSingleton> ps = JSingleton::Instance(); //정상적으로 해제 됨
	JSingleton* ps = JSingleton::Instance(); //소멸자 호출 안 됨
	ps->Test();

	return 0;
}
위와 같이 작성하고 실행해봤습니다.
그런데 소멸자가 호출이 되지 않네요.
JSingleton* ps을 로컬(메인 함수 내에서)로 선언하였으니 당연히 메인 함수가 끝날 때 소멸자가 실행이
될 것으로 예상했지만 안되더군요.
JSingleton::_instance 멤버가 static으로 되어있어서 그런 걸까요?
그래서 메인 함수의 끝나는 지점에

Code: Select all

delete ps;
라고 넣어봤는데 delete가 두번 실행되는 듯 합니다.(외부에서 한번, 소멸자에서 또 한번 실행 됨)
제가 의도한 것은 종료직전에 외부적인 호출 없이도 객체내에서 스스로 메모리가 해제되고
delete가 한번만 실행되는 겁니다.
auto_ptr을 사용하지 않고도 말이죠.
어떤 방법이 있을까요.
생성을 new로 했기때문에 delete를 하지 않는 이상 소멸자가 호출되지 않습니다.
그래서 위에 소스데로 하면 소멸자는 호출되지 않습니다

delete를 하면.. 더 문제가 심각해집니다.
자기 자신을 delete를 했기때문에 자기 자신에 대한 소멸자가 또 호출됩니다
소멸자가 재귀호출됩니다..

좀다 다른 구조를 생각해보셔야 할듯.

하지만 또 한가지 말씀드릴껀
전역또는 static 으로 생성하는 것 또한 추천하지 않습니다
메모리 할당 시점이라던지를 사용자가 정해줄수 없기 때문입니다.

new로 하는 방법을 조금 더 생각해 보심을 추천드립니다.^^
비회원

^^

Post by 비회원 »

좋은 의견들 감사드립니다.
new의 방법을 사용할 때 클래스의 내부에서 new로 생성된 힙을 반환하고
그것의 해제를 외부로 떠넘기는 것 역시 좋을 것 같지 않네요.
사용자 입장에서는 JSingleton::Instace() 함수가 반환하는 객체가 정적인지 동적할당인지 모를 수고 있겠구요.
쉬운 문제는 아니네요.
mastercho
Posts: 587
Joined: 2004-05-09 20:37

Re: 개념은 가장 명확하지만 구현이 의외로 어렵습니다.

Post by mastercho »

비회원 wrote:
싱글턴에서 생성방식이 정적객체를 이용하였을때는 생성소멸의 우선순위 문제가 있습니다.

컴파일러마다 제각각 전역객체를 임의로 생성과 소멸을 하기때문에

객체간 생성소멸의 우선순위는 보장할수없습니다.

그런 이유로 자유영역(Heap)에 올리는 것입니다.


ps.
저는 c++을 9년가량 공부했지만 singleton 이 가장 구현하기 까다로웠습니다.
100% 그 규약을 맞추기가 쉽지않더군요.
이것은 아마도 oop를 적극적으로 cover하지 못하는 c++의 한계가 아닐까 생각합니다.
c#과 java 등 에서는 어떻게 구현했을런지 궁금하군요.
모던 디자인 패턴을 보면 , 우선순위를 설정할수 있는 싱글턴과 , 죽었던 싱글턴을 되살려 처리하는

피닉스 싱글턴 등등이 있습니다

도움이 될거 같네요


다른 언어 역시 싱글턴이 소멸할때는 C++이 가졌던 문제를 피해갈순 없을거 같습니다
소멸 우선순위문제는 언어 문제라 보기 힘듭니다
gimmesilver
Posts: 85
Joined: 2005-10-23 05:46
Location: NCsoft openmaru studio
Contact:

C++ 싱글톤 구현

Post by gimmesilver »

이글을 참고하세요.
http://agbird.egloos.com/4730538
lee3075
Posts: 1
Joined: 2008-07-08 15:01

소멸자에 delete를 넣으셨는데 순서가 바뀌었습니다

Post by lee3075 »

소멸자가 먼저 호출이 되지 않습니다 delete 후에 소멸자가 호출되어집니다
강한상이가되자
Locked