主页 > 人工智能  > 

「软件设计模式」单例模式(Singleton)

「软件设计模式」单例模式(Singleton)
深入解析单例模式:从思想到C++实战实现

一、设计模式与单例模式思想 1.1 设计模式的价值

设计模式是软件工程领域的经验结晶,如同建筑领域的经典蓝图。它们提供了经过验证的解决方案模板,能有效解决以下问题:

提高代码复用性提升系统可维护性增强代码可读性降低模块耦合度 1.2 单例模式核心思想

单例模式(Singleton Pattern)确保一个类:

仅有一个实例存在提供全局访问点严格控制实例化过程

适用场景包括:

配置管理器日志记录器线程池数据库连接池硬件接口访问 二、C++实现方案对比 2.1 基础懒汉式(线程不安全)

#include <iostream> using namespace std; // 基础懒汉模式,非线程安全 class Singleton { public: static Singleton* getInstance() { if (!instance) { instance = new Singleton(); } return instance; } void doSomething() { cout << "Doing something..." << endl; } // 删除拷贝构造函数和赋值运算符 Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; private: Singleton() = default; ~Singleton() = default; static Singleton* instance; }; // 初始化静态成员 Singleton* Singleton::instance = nullptr; #include <thread> #include <vector> void threadFunction(int i) { Singleton* singleton = Singleton::getInstance(); cout << "Thread " << i << " Singleton address: " << singleton << endl; singleton->doSomething(); } int main() { const int numThreads = 10; std::vector<std::thread> threads; for (int i = 0; i < numThreads; ++i) { threads.emplace_back(threadFunction, i); } for (auto& thread : threads) { thread.join(); } return 0; }

 运行结果:可以看出非线程安全的,创建了两个实例。

2.2 线程安全双检锁(C++11+)

#include <iostream> #include <mutex> #include <thread> #include <vector> using namespace std; class ThreadSafeSingleton { public: static ThreadSafeSingleton* getInstance() { if (!instance) { std::lock_guard<std::mutex> lock(mutex); if (!instance) { instance = new ThreadSafeSingleton(); } } return instance; } void doSomething() { cout << "Doing something..." << endl; } private: static ThreadSafeSingleton* instance; static std::mutex mutex; }; // 初始化静态成员 ThreadSafeSingleton* ThreadSafeSingleton::instance = nullptr; std::mutex ThreadSafeSingleton::mutex; #include <thread> #include <vector> #include "lazy_single_thread_safe.h" void LazySafeThreadFunction(int i) { ThreadSafeSingleton* singleton = ThreadSafeSingleton::getInstance(); cout << "Thread Safe" << i << " Singleton address: " << singleton << endl; singleton->doSomething(); } // 线程安全懒汉模式 demo int main() { const int numThreads = 10; std::vector<std::thread> threads1; for (int i = 0; i < numThreads; ++i) { threads1.emplace_back(LazySafeThreadFunction, i); } for (auto& thread : threads1) { thread.join(); } return 0; }

 运行结果:线程安全。

2.3 现代C++实现(最优方案)

#include <iostream> using namespace std; /*** * 饿汉式 是否 Lazy 初始化:否 是否多线程安全:是 描述:这种方式比较常用,但容易产生垃圾对象。 优点:没有加锁,执行效率会提高。 缺点:类加载时就初始化,浪费内存。 它基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。 */ #include <iostream> class EagerSingleton { public: // 获取单例实例的静态方法 static EagerSingleton* getInstance() { static EagerSingleton instance; // 在第一次调用时创建实例 return &instance; } // 删除拷贝构造函数和赋值运算符,防止复制 EagerSingleton(const EagerSingleton&) = delete; EagerSingleton& operator=(const EagerSingleton&) = delete; // 示例方法 void doSomething() { cout << "Doing something..." << endl; } private: // 私有构造函数,防止外部实例化 EagerSingleton() { std::cout << "EagerSingleton instance created." << std::endl; } };

main 调用者:

#include <thread> #include <vector> #include "eager_single.h" void EagerSingletonThreadFunction(int i) { EagerSingleton* singleton = EagerSingleton::getInstance(); cout << "Thread Safe" << i << " Singleton address: " << singleton << endl; singleton->doSomething(); } // 线程安全懒汉模式 demo int main() { const int numThreads = 10; std::vector<std::thread> threads2; for (int i = 0; i < numThreads; ++i) { threads2.emplace_back(EagerSingletonThreadFunction, i); } for (auto& thread : threads2) { thread.join(); } return 0; }

运行结果:

方案对比表:

特性基础懒汉式双检锁现代实现线程安全❌✔️✔️延迟初始化✔️✔️✔️自动析构❌❌✔️C++标准要求-≥11≥11实现复杂度简单中等简单 三、关键实现细节解析 3.1 线程安全保证 现代实现方案利用C++11的静态变量初始化特性编译器保证静态局部变量的线程安全双检锁方案需要内存屏障支持 3.2 资源管理 现代方案自动处理析构指针方案需要自定义销毁逻辑可结合智能指针优化: #include <memory> class SmartSingleton { public: static SmartSingleton& getInstance() { static auto instance = std::make_shared<SmartSingleton>(); return *instance; } // ...其他成员... }; 3.3 继承扩展方案 template <typename T> class InheritableSingleton { public: static T& getInstance() { static T instance; return instance; } protected: InheritableSingleton() = default; virtual ~InheritableSingleton() = default; }; class MyLogger : public InheritableSingleton<MyLogger> { friend class InheritableSingleton<MyLogger>; // 具体实现... }; 四、最佳实践与陷阱规避 4.1 使用建议 优先选择现代实现方案明确单例的生命周期做好线程安全测试考虑依赖注入替代方案 4.2 常见陷阱 循环依赖问题测试困难(使用虚函数增加可测试性)多线程环境下的初始化竞争异常安全性问题 4.3 性能考量 现代方案无锁设计效率最高双检锁方案需要权衡锁开销饿汉式初始化可能影响启动速度 五、演进与替代方案 5.1 单例模式演进 多例模式(Multiton)线程局部单例集群环境单例 5.2 现代替代方案 依赖注入容器全局命名空间函数(权衡使用)服务定位器模式 六、总结

单例模式作为创建型模式的代表,在特定场景下能有效管理系统资源。但需要注意:

不要滥用导致全局状态污染优先考虑依赖注入等现代方案关注线程安全和生命周期管理

正确使用单例模式,可以构建出高效、可控的软件系统。但记住,好的架构应该是灵活可扩展的,而不是充满各种全局状态的"单例陷阱"。

示例代码已在GCC 13.1和Clang 16.0测试通过,建议使用C++17及以上标准编译。实际项目中请根据具体需求选择合适的实现方案。

标签:

「软件设计模式」单例模式(Singleton)由讯客互联人工智能栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“「软件设计模式」单例模式(Singleton)