본문 바로가기

프로그래밍/C++

[C++] 선언 없이 단 한 번만 실행되기

무언가 프로그램이 시작하고 끝날 때까지
단 한 번만 실행되었으면 좋겠다.


사실 이것은 단일체(Singleton)의 목적이라고 할 수 있습니다.
헌데, 그것과는 오묘히 다릅니다.
단일체는 단 한 개의 객체를 보장받기 위해서 일반적으로 사용합니다.
지금 말하고자 하는 것은 단 한 개의 객체가 아니라
단 한 번만 실행되는 무엇입니다ㅣ.
객체를 이용할 것도 아니고 그저 프로세스 전체에서
단 하나를 실행시키는 그 무엇 말입니다.

이미 알려진 방법이 있을 수도 있겠는데
제가 생각해낸 방법은 다음과 같습니다.

이것은 Singleton Pattern에 나온 정의입니다.

class Singleton{
public:
static Singleton getInstance(){ return selfInstance; }

private:
SIngleton();
static Singleton *selfInstance = new Singleton();
};

처음에 전역변수 selfInstance를 초기화해주기 때문에
프로세스가 시작하기 전 Singleton()이 불리게 됩니다.
따로 객체의 다른 것들이 불리지 않아도
무조건 Singleton()은 실시되도록 되어있죠.

하지만 이 녀석의 문제는 바로 소멸을 시켜주지 않는 것입니다.
포인터를 new로 선언해주었기에
무조건 delete를 해주어야 된다는 것이지요.
생성도 명시적으로 하지 않았는데
소멸을 명시적으로 한다는 것은 정말
하늘이 통탄하고 땅이 하늘을 칠 일입니다 !

하지만 실상 해답은 간단한 데에 있었습니다.
포인터를 안 쓰면 되는 것이지요.
즉,

static Singleton s;

를 선언하면 되는 것입니다.
하지만 이 때 우리가 지역에 선언하듯

static Singleton s;

혹은

static Singleton s();

이렇게 해서는
생성자가 불리지 않습니다.
( 컴파일은 됩니다. )

따라서 여기서는 생성자를 명시적으로 불러준 뒤에 치환을 하도록 해야합니다.

Singleton Singleton::selfInstance = Singleton();

이것은 마치 전역변수를 선언하고 함수의 반환값을 치환한 것과 같은 결과입니다.

int func(void)
{
printf( "1
" );
return 0;
}

static int var = func();
여기서는 1이 출력됩니다.


자, 그러면
" 그냥 전역 변수에서 실행하면 되지 뭐하러 클래스를 만드나요 ? "
이런 궁금이 나는 분들이 계신가요 ?
이유는,
" 소멸자를 부르기 위해서입니다. "

클래스의 장점은 역시 소멸자를 불러준데에 있죠.
단지 함수로 놔두는 것은
포인터로 하는 것과 메모리 해제 여부의 차이만 있을뿐,
소멸이 되지 않는 것은 똑같습니다.
소멸자를 예약하기 위해 제일 간편한 것은 바로 클래스인 겝니다.

자, 마지막은 예제와 함께 설명하도록 하겠습니다.
제가 이것을 갈구했던 이유는 바로
WSAStartUp()과 WSACleanUp() 때문입니다.
( Winsock을 초기화하기 위한 함수들입니다. )
MSDN에 써있기로는
윈속을 이용하기 전에 WSAStartUp()을 한 번만 실행하면 된다고 하고 있습니다.
WSAStartUp()의 호출은 계속적으로 이루어져도 되지만
WSAStartUp()을 호출한 만큼 WSACleanUp()가 불려져야 된다고 하고 있습니다.
그래서 저와 같은 패턴을 생각하게 된것입니다.

그래서 만들어진 파일은 다음과 같습니다.

=-= WSAManager.h
#pragma once
#include

class WSAManager
{
private:
WSAManager(void);
~WSAManager(void);
static WSAManager self;
};

=-= WSAManager.cpp
#include ".wsamanager.h"
WSAManager WSAManager::self = WSAManager();

WSAManager::WSAManager(void)
{
WSADATA info;
WSAStartup(MAKEWORD(2,0), &info);
}

WSAManager::~WSAManager(void)
{
WSACleanup();
}


이제 이 파일은 단순히 #include해준 것으로
딱 한 번만 실행되도록 보장받을 수 있습니다 !
크.. 크고 훌륭합니다 !
( 이게 정말 괜찮은 해결책일지는 아직 잘 모르겠습니다.
더 좋은 방법이 있다면 일러주세요. ^-^ )

'프로그래밍 > C++' 카테고리의 다른 글

[C++] 헤더파일을 나누어 은닉화 구현하기  (0) 2007.01.26
[C++] Insertion Sequance( std::vector, ... )  (4) 2006.04.19
단일체  (8) 2006.03.08
Java의 Package  (0) 2006.02.22
[C++]예외 처리  (0) 2006.02.03