单例模式是最简单的设计模式,就让我像玩简单的游戏一样写下去吧。
v1: 简单模式
和这个版本有过一面之缘,但不敢苟同。
class Singleton { private: Singleton() {} public: static Singleton * getIns() { static Singleton * ins = new Singleton(); return ins; } };
问题:何时析构不明确;最重要的是调用多次getIns函数会产生多个static Singleton指针,指向每次都调用都new出来的实例。
v2: 一般模式
典型写法
class Singleton { private: Singleton() {} static Singleton * ins; public: static Singleton * getIns() { if(!ins) ins = new Singleton(); return ins; } }; static Singleton * Singleton::ins = NULL;
问题:仍然未考虑析构问题;对象可能被复制出多个副本。
Java中由于允许在调用构造函数之前先初始化变量,因此有这样一种写法:
public class Singleton { private Singleton() {} public static Singleton ins = new Singleton(); public static Singleton * getIns() { return ins; } };
简洁明了,也是蛮OK啦,析构也省了,并且由于初始化这个语句是JVM做的,因此人工的同步也省了(不带这么欺负C++程序员的 = =)。
v2.1 一般模式2
v3: 加强模式
加入私有的复制构造函数以防出现单例对象的副本;加入一个内部静态类,整个程序结束后,静态类随着其他静态变量消亡,此时调用析构函数将ins析构。
class Singleton { private: Singleton() {} Singleton(const Singleton & s) {} Singleton & operator = (const Singleton & s) {} static Singleton * ins; public: static Singleton * getIns() { if(!ins) ins = new Singleton(); return ins; } class CGarbo // 内部类 { public: ~CGarbo() { if(Singleton::ins) delete Singleton::ins; } }; static CGarbo Garbo; }; static Singleton * Singleton::ins = NULL;
问题:不是线程安全的。
v4: hard模式
static Singleton * getIns() { pthread_mutex_init( &mutex_lock ); if(!ins) ins = new Singleton(); pthread_mutex_destory( &mutex_lock ); return ins; }
问题:不管ins是不是空,都要加锁,代价高
v5: 再接再励模式
当ins不为空时,反正getIns函数不管读写,直接返回就好了,读写锁尽可交给使用者。
static Singleton * getIns() { if(!ins) { pthread_mutex_init( &mutex_lock ); if(!ins) ins = new Singleton(); pthread_mutex_destory( &mutex_lock ); } return ins; }
自然,getIns加了锁,析构的时候也同样要加锁。继续学习,再接再励!
时间: 2024-10-17 10:28:45