1. Singleton이란?
Singleton은 디자인 패턴 중 하나로, 프로그램 전체에서 클래스의 인스턴스를 하나만 생성하도록 제한하고, 그 인스턴스에 전역적으로 접근할 수 있게 만드는 방식이다.
하지만 전역 인스턴스를 만드는 것이기 때문에, 잘못 사용하면 전역 변수와 같은 문제를 야기할 수 있으므로 신중하게 사용해야 한다.
2. 기본 구현 방법
아래는 가장 간단한 싱글톤 구현 예제이다.
class Singleton
{
public:
static Singleton& getInstance()
{
static Singleton instance; // C++11 이후 thread-safe
return instance;
}
void doSomething()
{
// 어떤 작업
}
private:
Singleton() {} // 외부에서 생성 불가
~Singleton() {}
};
✅ 포인트 요약
- 생성자를 private으로 선언하여 외부에서 인스턴스를 만들 수 없도록 한다.
- getInstance()는 정적 함수로 하나의 인스턴스를 반환한다.
3. Thread-safe Singleton
C++11부터는 static local variable이 스레드 안전(thread-safe)하게 초기화되므로 위의 구현은 멀티스레드 환경에서도 안전하다.
- 오래된 코드를 보면 mutex를 이용하여 수동 동기화를 했는데, C++11부터는 그럴 필요가 없다 !
4. 생성 방법 : Lazy vs Eager Initialization
Singleton은 생성 방법에 따라 두가지로 나뉜다.
4-1) 💤 Lazy Initialization (지연 초기화)
Singleton 인스턴스를 내가 실제로 필요할 때 생성하는 방식
class Singleton {
public:
static Singleton& getInstance() {
static Singleton instance; // 최초 호출 시에만 생성됨
return instance;
}
private:
Singleton() {}
};
✅ 장점
- 사용하지 않으면 생성되지 않으므로 리소스를 절약할 수 있음.
- 생성 순서를 명확하게 제어할 수 있음 (사용 시점 = 생성 시점).
- C++11 이후에는 static 지역 변수의 초기화가 thread-safe하므로 동기화 걱정이 없음.
❌ 단점
- 초기화 타이밍이 예측되지 않음: 프로그램 흐름에 따라 인스턴스가 언제 생기는지 명확하지 않을 수 있음.
- 프로그램 종료 시 파괴 순서 문제가 생길 수 있음 (특히 여러 static 객체와 얽혀 있을 때).
4-2) ⚡ Eager Initialization (즉시 초기화)
프로그램 시작 시점에 미리 생성해두는 방식
class Singleton {
public:
static Singleton& getInstance() {
return instance;
}
private:
Singleton() {}
static Singleton instance; // main 전에 이미 생성됨
};
Singleton Singleton::instance;
✅ 장점
- 초기화 타이밍이 정해져 있어서 예측 가능.
- 여러 객체가 동시에 의존할 경우 초기화 순서 문제를 줄일 수 있음.
❌ 단점
- 실제로 쓰이지 않더라도 생성됨 → 불필요한 리소스 사용 가능성.
- 생성 시점에 예외가 발생하면, 프로그램이 시작도 못 하고 실패할 수 있음.
4-3) ✍️ 언제 어떤 걸 써야할까?
- Lazy가 기본 선택: 대부분의 경우에 효율적이고 간단함.
- Eager는 다음과 같은 상황에 유용:
- 초기화 순서가 명확해야 하는 복잡한 시스템
- 반드시 생성되어야만 하는 critical 자원
- 프로그램 시작 단계에서 무조건 사용됨이 보장될 때
5. Singleton의 단점
이렇게만 보면 무적인 거 같지만, 당연히 단점도 존재한다는 사실 !
- 테스트 어려움: 전역 인스턴스를 mocking하기 어렵다.
- 의존성 숨김: 클래스 내부에서 몰래 singleton을 참조하면 추적이 어렵다.
- 멀티스레드 문제: 잘못 구현되면 race condition 발생 가능.
- 라이프사이클 제어 어려움: 생성 시점, 소멸 시점을 제어하기 힘들다.
이 때문에 무분별한 singleton 사용은 코드 품질을 악화시킬 수 있다.
6. 마무리 : 언제 Singleton을 쓸 것인가?
Singleton은 다음 조건을 만족할 때만 사용하는 것이 좋다:
- 인스턴스가 하나만 존재해야 하는 강한 논리적 이유가 있을 때
- 해당 인스턴스에 전역적으로 접근할 필요가 있을 때
- 멀티스레드 환경에서 정상적으로 동작하도록 설계되었을 때
가능하다면 Singleton 대신 의존성 주입이나 명시적 객체 전달을 사용하는 것이 유지보수와 테스트 측면에서 훨씬 유리하다.
'💻 Computer Science > C,C++' 카테고리의 다른 글
[C++] ini 파일 파라미터 읽기 및 쓰기 (0) | 2025.04.15 |
---|---|
[C++] 코드 한줄로 이더넷 ip, subnetmask, gateway 변경하기 : PowerShell 명령어 (0) | 2025.04.08 |
[C++] 각도 제한 [ -pi ~ pi ] (0) | 2024.03.01 |
[C++] Quaternion to Euler 상호 변환 (0) | 2024.03.01 |
[C++] 알고리즘 수행 시간 측정 (0) | 2024.02.21 |