Singleton Pattern đảm bảo một lớp chỉ có một instance duy nhất và cung cấp điểm truy cập toàn cục đến instance đó.
Cài đặt cơ bản (C++98 style)
#include <iostream>
class Singleton {
private:
static Singleton* instance; // Con trỏ static đến instance duy nhất
int data;
// Private constructor - không cho phép tạo từ bên ngoài
Singleton() : data(0) {}
// C++11: Xóa copy/move
// Singleton(const Singleton&) = delete;
// Singleton& operator=(const Singleton&) = delete;
public:
static Singleton* getInstance() {
if (!instance) {
instance = new Singleton(); // Lazy initialization
}
return instance;
}
int getData() const { return data; }
void setData(int d) { data = d; }
// Cleanup (tùy chọn)
static void destroy() {
delete instance;
instance = nullptr;
}
};
// Khởi tạo static member
Singleton* Singleton::instance = nullptr;
int main() {
Singleton* s = Singleton::getInstance();
std::cout << s->getData() << std::endl; // 0
s->setData(100);
std::cout << s->getData() << std::endl; // 100
Singleton::destroy();
}
Kết quả
0 100
Vấn đề với cách trên
- Không thread-safe: Hai thread cùng gọi
getInstance()có thể tạo 2 instance - Rò rỉ bộ nhớ nếu quên
destroy() - Thứ tự hủy static object không xác định
C++11: Thread-safe Singleton (Meyer's Singleton)
class Singleton {
private:
Singleton() = default;
~Singleton() = default;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
public:
static Singleton& getInstance() {
static Singleton instance; // C++11: Khởi tạo thread-safe
return instance;
}
int data = 0;
};
// Sử dụng:
Singleton& s = Singleton::getInstance();
s.data = 42;
Ưu điểm Meyer's Singleton
- Thread-safe (C++11 đảm bảo static local init an toàn)
- Không cần quản lý bộ nhớ thủ công
- Hủy tự động khi chương trình kết thúc
- Lazy initialization (tạo khi đầu tiên dùng)
Eager Initialization (Khởi tạo sớm)
class Singleton {
private:
static Singleton instance; // Tạo ngay khi load program
Singleton() {}
public:
static Singleton& getInstance() { return instance; }
};
Singleton Singleton::instance; // Định nghĩa
Singleton với dependency injection (Testable)
class Logger {
public:
virtual void log(const std::string& msg) = 0;
virtual ~Logger() = default;
};
class FileLogger : public Logger {
// ...
};
class App {
Logger& logger; // Dependency inject
public:
App(Logger& l) : logger(l) {}
void run() { logger.log("Start"); }
};
// Test: Truyền MockLogger
// Production: Truyền FileLogger
Khi nào dùng Singleton?
- Logger, Configuration, Cache, Connection Pool
- Hardware interface (GPU, GPIO...)
- Khi thực sự cần một instance toàn cục
Khi nào KHÔNG dùng
- Chỉ để tránh truyền tham số (global state ẩn)
- Khi cần multiple instances cho test
- Khi vi phạm Single Responsibility Principle
Tóm tắt
C++11+: Dùng Meyer's Singleton (static local trong function) — đơn giản, thread-safe, RAII. Tránh con trỏ raw + new/delete.