싱글톤(Singleton) 디자인 패턴은 하나의 클래스에 대해 오직 단 하나의 객체(인스턴스)만 생성되도록 제한하는 소프트웨어 설계 원칙입니다. 시스템 전체에서 하나의 객체만으로 동작을 조율해야 할 때 매우 유용하게 사용됩니다.
예를 들어, 파일에 로그를 기록하는 로거(Logger)를 생각해 볼 수 있습니다. 여러 곳에서 로그를 남기더라도 파일 접근은 한 곳에서만 관리하는 것이 안전하므로, 이런 경우 싱글톤 클래스로 로거를 구현하는 것이 좋습니다.
싱글톤 패턴의 핵심 구현 요소
C++에서 싱글톤 클래스를 만들려면 다음 세 가지가 필요합니다.
1. private 생성자 — 외부에서 객체를 직접 생성하지 못하도록 막습니다.
2. static 멤버 변수 — 유일한 인스턴스의 주소를 저장합니다.
3. static getInstance() 메서드 — 인스턴스가 없으면 새로 만들고, 있으면 기존 인스턴스를 반환합니다.
예제 코드
#include <iostream>
using namespace std;
class Singleton {
static Singleton *instance;
int data;
// private 생성자: 외부에서 객체 생성 불가
Singleton() {
data = 0;
}
public:
static Singleton *getInstance() {
if (!instance)
instance = new Singleton;
return instance;
}
int getData() {
return this -> data;
}
void setData(int data) {
this -> data = data;
}
};
// 첫 번째 getInstance() 호출 시 초기화될 수 있도록 포인터를 0으로 초기화
Singleton *Singleton::instance = 0;
int main() {
Singleton *s = s->getInstance();
cout << s->getData() << endl;
s->setData(100);
cout << s->getData() << endl;
return 0;
}실행 결과
0 100
동작 원리 설명
main 함수에서 getInstance()를 처음 호출하면 instance 포인터가 null이므로 새로운 Singleton 객체가 생성됩니다. 이후 아무리 getInstance()를 다시 호출해도 항상 같은 객체가 반환되며, setData(100)로 변경한 값은 어느 위치에서 접근해도 동일하게 유지됩니다.
주의 사항: 스레드 안전성
위 예제는 단일 스레드 환경을 전제로 합니다. 멀티 스레드 환경에서는 두 스레드가 동시에 getInstance()에 진입해 인스턴스가 두 개 생성될 위험이 있습니다. C++11 이상에서는 지역 static 변수의 초기화가 스레드 안전하다는 점을 활용해 다음과 같이 개선할 수 있습니다.
static Singleton& getInstance() {
static Singleton instance; // C++11부터 스레드 안전 보장
return instance;
}이처럼 싱글톤 패턴은 로거, 설정 관리자, 데이터베이스 연결 풀처럼 시스템 전체에서 공유되어야 하는 자원을 관리할 때 널리 활용됩니다.