싱글톤 패턴 (Singleton Pattern)
싱글톤 패턴은 특정 클래스의 인스턴스가 하나만 존재하도록 보장하고, 그 인스턴스에 대한 전역 접근점을 제공하는 디자인 패턴입니다. 이는 전역 상태를 관리하거나, 리소스를 공유해야 하는 상황에서 유용합니다.
싱글톤 패턴의 특징
- 유일한 인스턴스: 클래스의 인스턴스가 하나만 존재함을 보장합니다.
- 전역 접근점: 유일한 인스턴스에 대한 전역 접근을 제공합니다.
- 게으른 초기화: 인스턴스가 처음 필요할 때 생성됩니다.
기본 싱글톤 패턴 구현
싱글톤 패턴을 구현하는 방법은 여러 가지가 있지만, 여기서는 가장 일반적인 구현 방법을 소개합니다.
싱글톤 클래스 정의
#include <iostream>
#include <mutex>
class Singleton {
private:
static Singleton* instance;
static std::mutex mtx;
// 생성자를 private으로 정의하여 외부에서 객체 생성을 막습니다.
Singleton() {}
public:
// 복사 생성자와 대입 연산자를 삭제합니다.
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
// 유일한 인스턴스를 얻는 정적 메서드
static Singleton* getInstance() {
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mtx);
if (instance == nullptr) {
instance = new Singleton();
}
}
return instance;
}
void showMessage() {
std::cout << "Hello from Singleton!" << std::endl;
}
};
// 정적 멤버 변수 초기화
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;
int main() {
Singleton* s1 = Singleton::getInstance();
s1->showMessage();
Singleton* s2 = Singleton::getInstance();
s2->showMessage();
// 두 포인터가 동일한 인스턴스를 가리키는지 확인
if (s1 == s2) {
std::cout << "s1 and s2 are the same instance." << std::endl;
}
return 0;
}
이 예제에서 Singleton
클래스는 getInstance
메서드를 통해 유일한 인스턴스를 제공합니다. 인스턴스가 처음 필요할 때 생성되며, 이 과정은 스레드 안전하게 구현되었습니다.
싱글톤 패턴의 변형
싱글톤 패턴의 구현은 다양한 방법으로 변형될 수 있습니다. 몇 가지 일반적인 변형을 소개하겠습니다.
마이어스의 싱글톤 (Meyers' Singleton)
마이어스의 싱글톤은 C++11 이후의 표준에서 안전한 정적 지역 변수를 사용하여 싱글톤을 구현합니다. 이 방법은 간결하고, 스레드 안전성을 보장합니다.
#include <iostream>
class Singleton {
public:
// 인스턴스를 얻는 정적 메서드
static Singleton& getInstance() {
static Singleton instance; // 정적 지역 변수
return instance;
}
void showMessage() {
std::cout << "Hello from Meyers' Singleton!" << std::endl;
}
private:
// 생성자를 private으로 정의하여 외부에서 객체 생성을 막습니다.
Singleton() {}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
int main() {
Singleton& s1 = Singleton::getInstance();
s1.showMessage();
Singleton& s2 = Singleton::getInstance();
s2.showMessage();
// 두 참조가 동일한 인스턴스를 가리키는지 확인
if (&s1 == &s2) {
std::cout << "s1 and s2 are the same instance." << std::endl;
}
return 0;
}
이 예제에서 Singleton
클래스는 getInstance
메서드를 통해 정적 지역 변수로 유일한 인스턴스를 제공합니다. 이 방법은 초기화 시점에 스레드 안전성을 보장합니다.
싱글톤 패턴의 활용 사례
싱글톤 패턴은 다양한 상황에서 유용하게 사용될 수 있습니다. 몇 가지 일반적인 활용 사례를 소개하겠습니다.
- 로깅 클래스: 애플리케이션의 로그를 관리하는 클래스는 하나의 인스턴스만 있어야 합니다.
- 설정 클래스: 애플리케이션의 설정 정보를 관리하는 클래스는 전역에서 접근할 수 있어야 합니다.
- 스레드 풀: 리소스를 효율적으로 관리하기 위해 스레드 풀을 싱글톤으로 구현할 수 있습니다.
실습 문제
문제 1: 싱글톤 패턴을 사용하여 로깅 클래스 구현
싱글톤 패턴을 사용하여 로깅 클래스를 구현하고, 여러 번의 로그 메시지를 기록하는 프로그램을 작성하세요.
해설:
#include <iostream>
#include <mutex>
#include <fstream>
class Logger {
private:
static Logger* instance;
static std::mutex mtx;
std::ofstream logFile;
Logger() {
logFile.open("log.txt", std::ios::app);
}
public:
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
static Logger* getInstance() {
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mtx);
if (instance == nullptr) {
instance = new Logger();
}
}
return instance;
}
void logMessage(const std::string& message) {
std::lock_guard<std::mutex> lock(mtx);
logFile << message << std::endl;
}
~Logger() {
if (logFile.is_open()) {
logFile.close();
}
}
};
Logger* Logger::instance = nullptr;
std::mutex Logger::mtx;
int main() {
Logger* logger = Logger::getInstance();
logger->logMessage("This is the first log message.");
logger->logMessage("This is the second log message.");
return 0;
}
문제 2: 마이어스의 싱글톤을 사용하여 설정 클래스를 구현
마이어스의 싱글톤을 사용하여 애플리케이션 설정 정보를 관리하는 설정 클래스를 구현하세요.
해설:
#include <iostream>
#include <string>
class Config {
private:
std::string setting;
Config() : setting("default") {}
public:
Config(const Config&) = delete;
Config& operator=(const Config&) = delete;
static Config& getInstance() {
static Config instance;
return instance;
}
void setSetting(const std::string& newSetting) {
setting = newSetting;
}
std::string getSetting() const {
return setting;
}
};
int main() {
Config& config = Config::getInstance();
std::cout << "Initial setting: " << config.getSetting() << std::endl;
config.setSetting("custom setting");
std::cout << "Updated setting: " << config.getSetting() << std::endl;
return 0;
}
이제 8일차의 학습을 마쳤습니다. 싱글톤 패턴의 다양한 구현 방법과 활용 사례에 대해 상세히 학습하고 실습 문제를 풀어보았습니다.
질문이나 피드백이 있으면 언제든지 댓글로 남겨 주세요. 내일은 "팩토리 패턴"에 대해 학습하겠습니다.
'-----ETC----- > C++ 고급 프로그래밍과 응용 프로젝트 시리즈' 카테고리의 다른 글
[C++ 고급 프로그래밍과 응용 프로젝트 시리즈] Day 10: 디자인 패턴 심화 - 전략 패턴 (Strategy Pattern) (0) | 2024.08.01 |
---|---|
[C++ 고급 프로그래밍과 응용 프로젝트 시리즈] Day 7: R-값 참조와 이동 시멘틱 (0) | 2024.08.01 |
[C++ 고급 프로그래밍과 응용 프로젝트 시리즈] Day 5: 범위 기반 for 루프와 초기화 리스트 (0) | 2024.08.01 |
[C++ 고급 프로그래밍과 응용 프로젝트 시리즈] Day 6: constexpr과 상수 표현식 (0) | 2024.08.01 |
[C++ 고급 프로그래밍과 응용 프로젝트] Day 3: SFINAE와 개념 (0) | 2024.08.01 |