1. 什么是单例模式?
单例模式确保一个类只有一个实例,并提供一个全局访问点。
生活比喻:
公司只有一个CEO:
- 无论哪个部门要找CEO,找到的都是同一个人
- CEO的职位是唯一的,不能有多个CEO
- 大家通过固定的方式联系CEO
2. 基本的单例模式实现
2.1 懒汉式(线程不安全)
class Singleton {
private:
static Singleton* instance; // 静态实例指针
Singleton() {} // 私有构造函数
Singleton(const Singleton&) = delete; // 禁止拷贝
Singleton& operator=(const Singleton&) = delete; // 禁止赋值
public:
static Singleton* getInstance() {
if (instance == nullptr) {
instance = new Singleton();
}
return instance;
}
void showMessage() {
std::cout << "Singleton Instance: " << this << std::endl;
}
};
// 静态成员初始化
Singleton* Singleton::instance = nullptr;
3. 线程安全的单例模式
3.1 懒汉式 + 互斥锁(线程安全)
#include <mutex>
class ThreadSafeSingleton {
private:
static ThreadSafeSingleton* instance;
static std::mutex mtx; // 互斥锁
ThreadSafeSingleton() {
std::cout << "Singleton created!" << std::endl;
}
~ThreadSafeSingleton() {
std::cout << "Singleton destroyed!" << std::endl;
}
// 禁止拷贝和赋值
ThreadSafeSingleton(const ThreadSafeSingleton&) = delete;
ThreadSafeSingleton& operator=(const ThreadSafeSingleton&) = delete;
public:
static ThreadSafeSingleton* getInstance() {
std::lock_guard<std::mutex> lock(mtx); // 加锁
if (instance == nullptr) {
instance = new ThreadSafeSingleton();
}
return instance;
}
void businessLogic() {
std::cout << "Doing business logic..." << std::endl;
}
};
// 静态成员初始化
ThreadSafeSingleton* ThreadSafeSingleton::instance = nullptr;
std::mutex ThreadSafeSingleton::mtx;
3.2 双重检查锁定(优化性能)
class DoubleCheckedSingleton {
private:
static std::atomic<DoubleCheckedSingleton*> instance;
static std::mutex mtx;
DoubleCheckedSingleton() = default;
~DoubleCheckedSingleton() = default;
DoubleCheckedSingleton(const DoubleCheckedSingleton&) = delete;
DoubleCheckedSingleton& operator=(const DoubleCheckedSingleton&) = delete;
public:
static DoubleCheckedSingleton* getInstance() {
// 第一次检查(不加锁)
DoubleCheckedSingleton* temp = instance.load(std::memory_order_acquire);
if (temp == nullptr) {
std::lock_guard<std::mutex> lock(mtx);
// 第二次检查(加锁后)
temp = instance.load(std::memory_order_relaxed);
if (temp == nullptr) {
temp = new DoubleCheckedSingleton();
instance.store(temp, std::memory_order_release);
}
}
return temp;
}
};
std::atomic<DoubleCheckedSingleton*> DoubleCheckedSingleton::instance{nullptr};
std::mutex DoubleCheckedSingleton::mtx;
4. Meyers' Singleton(最推荐的现代实现)
4.1 局部静态变量方式(C++11后线程安全)
class MeyersSingleton {
private:
MeyersSingleton() {
std::cout << "Meyers Singleton created!" << std::endl;
}
~MeyersSingleton() {
std::cout << "Meyers Singleton destroyed!" << std::endl;
}
MeyersSingleton(const MeyersSingleton&) = delete;
MeyersSingleton& operator=(const MeyersSingleton&) = delete;
public:
static MeyersSingleton& getInstance() {
static MeyersSingleton instance; // C++11保证线程安全
return instance;
}
void showAddress() {
std::cout << "Instance address: " << this << std::endl;
}
};
5. 实际应用场景示例
5.1 配置文件管理器
#include <unordered_map>
#include <string>
class ConfigManager {
private:
std::unordered_map<std::string, std::string> config;
ConfigManager() {
// 加载默认配置
config["database.host"] = "localhost";
config["database.port"] = "3306";
config["app.name"] = "MyApp";
std::cout << "ConfigManager initialized" << std::endl;
}
~ConfigManager() = default;
ConfigManager(const ConfigManager&) = delete;
ConfigManager& operator=(const ConfigManager&) = delete;
public:
static ConfigManager& getInstance() {
static ConfigManager instance;
return instance;
}
void setConfig(const std::string& key, const std::string& value) {
config[key] = value;
}
std::string getConfig(const std::string& key) const {
auto it = config.find(key);
return it != config.end() ? it->second : "";
}
void printAllConfigs() const {
for (const auto& pair : config) {
std::cout << pair.first << " = " << pair.second << std::endl;
}
}
};
5.2 日志管理器
#include <fstream>
#include <iostream>
class Logger {
private:
std::ofstream logFile;
Logger() {
logFile.open("app.log", std::ios::app);
if (!logFile.is_open()) {
throw std::runtime_error("Cannot open log file");
}
logFile << "=== Application Started ===" << std::endl;
}
~Logger() {
if (logFile.is_open()) {
logFile << "=== Application Ended ===" << std::endl;
logFile.close();
}
}
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
public:
static Logger& getInstance() {
static Logger instance;
return instance;
}
void log(const std::string& message) {
if (logFile.is_open()) {
logFile << message << std::endl;
}
std::cout << "[LOG] " << message << std::endl;
}
void error(const std::string& message) {
if (logFile.is_open()) {
logFile << "[ERROR] " << message << std::endl;
}
std::cerr << "[ERROR] " << message << std::endl;
}
};
5.3 数据库连接池
#include <vector>
#include <memory>
class DatabaseConnection { /* ... */ };
class ConnectionPool {
private:
std::vector<std::unique_ptr<DatabaseConnection>> connections;
size_t maxConnections;
ConnectionPool() : maxConnections(10) {
initializePool();
}
void initializePool() {
for (size_t i = 0; i < maxConnections; ++i) {
connections.push_back(std::make_unique<DatabaseConnection>());
}
std::cout << "Connection pool initialized with "
<< maxConnections << " connections" << std::endl;
}
~ConnectionPool() {
connections.clear();
std::cout << "Connection pool destroyed" << std::endl;
}
ConnectionPool(const ConnectionPool&) = delete;
ConnectionPool& operator=(const ConnectionPool&) = delete;
public:
static ConnectionPool& getInstance() {
static ConnectionPool instance;
return instance;
}
DatabaseConnection* getConnection() {
// 简单的连接获取逻辑
if (!connections.empty()) {
auto connection = connections.back().release();
connections.pop_back();
return connection;
}
return nullptr;
}
void returnConnection(DatabaseConnection* connection) {
if (connection) {
connections.push_back(std::unique_ptr<DatabaseConnection>(connection));
}
}
};
6. 模板单例(通用实现)
cpp
template<typename T>
class Singleton {
protected:
Singleton() = default;
~Singleton() = default;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
public:
static T& getInstance() {
static T instance;
return instance;
}
};
// 使用方式
class MyManager : public Singleton<MyManager> {
friend class Singleton<MyManager>; // 允许Singleton访问私有构造函数
private:
MyManager() = default;
public:
void doWork() {
std::cout << "MyManager working..." << std::endl;
}
};
// 使用
// MyManager& manager = MyManager::getInstance();
7. 单例模式的优缺点
优点:
cpp
✅ 严格控制实例数量
✅ 全局访问点方便
✅ 延迟初始化(节省资源)
✅ 避免全局变量污染
缺点:
cpp
❌ 违反单一职责原则
❌ 隐藏类间的依赖关系
❌ 对单元测试不友好
❌ 在多线程环境需要特殊处理
8. 测试代码
cpp
#include <iostream>
#include <thread>
#include <vector>
void testSingleton() {
std::cout << "=== 单例模式测试 ===" << std::endl;
// 测试基本单例
auto& config1 = ConfigManager::getInstance();
auto& config2 = ConfigManager::getInstance();
std::cout << "config1 address: " << &config1 << std::endl;
std::cout << "config2 address: " << &config2 << std::endl;
std::cout << "是否是同一个实例: " << (&config1 == &config2) << std::endl;
// 测试配置功能
config1.setConfig("server.port", "8080");
std::cout << "端口配置: " << config2.getConfig("server.port") << std::endl;
}
void threadTask(int id) {
auto& logger = Logger::getInstance();
logger.log("Thread " + std::to_string(id) + " is working");
}
void testThreadSafety() {
std::cout << "\n=== 线程安全测试 ===" << std::endl;
std::vector<std::thread> threads;
for (int i = 0; i < 5; ++i) {
threads.emplace_back(threadTask, i);
}
for (auto& t : threads) {
t.join();
}
}
int main() {
testSingleton();
testThreadSafety();
return 0;
}
9. 面试常见问题
Q1:为什么要把构造函数设为private?
A:防止外部直接创建对象,确保只能通过getInstance()获取实例。
Q2:单例模式如何保证线程安全?
A:C++11后,局部静态变量的初始化是线程安全的;或者使用互斥锁。
Q3:单例模式的销毁问题?
A:通常让系统在程序结束时自动销毁,或者实现destroyInstance()方法。
Q4:单例模式 vs 全局变量?
A:单例提供更好的封装性、延迟初始化、继承可能性。
10. 总结
现代C++单例最佳实践:
cpp
class BestSingleton {
private:
BestSingleton() = default;
~BestSingleton() = default;
BestSingleton(const BestSingleton&) = delete;
BestSingleton& operator=(const BestSingleton&) = delete;
public:
static BestSingleton& getInstance() {
static BestSingleton instance; // ✅ 线程安全
return instance; // ✅ 自动销毁
}
};
记住关键点:
-
🎯 私有构造函数 + 删除拷贝操作
-
🚀 使用局部静态变量(C++11)
-
🔧 根据需求选择合适的线程安全方案
-
⚠️ 注意单例的适用场景,不要滥用
