单例模式简析

来源:互联网 发布:台湾政治知乎 编辑:程序博客网 时间:2024/05/21 07:48
一、单例模式
     单例模式确保一个类只有一个实例,自行提供这个实例并向整个系统提供这个实例。
     特点就是多读单写。
函数简单实现:
classSingleton
{
public:
       staticSingleton*GetInstance()//申明为static,可以由对象直接调用,不用用类调用
       {
              if(_sInstance ==NULL)
              {
                     _sInstance =newSingleton;
              }
              return_sInstance;
       }
       voidprintf()
       {
              cout << _data << endl;
       }
protected:
       Singleton()
              :_data(0)
       {}
       //防拷贝,只申明不定义
       Singleton(Singleton&);
       Singleton&operator=(Singleton&);
       //指向实例的指针定义为静态私有,这样定义静态成员函数获取对象实例
       staticSingleton* _sInstance;
private:
       int_data;
};
Singleton*Singleton::_sInstance = NULL;//初始化
intmain()
{
       Singleton::GetInstance()->printf();
       return0;
}

二、基于线程安全的改进
     若有两个线程同时访问单例模式获取对象的方法,thread1执行方法,第一次进入发现指针为NULL,在还没有new之前,thread2也进入,这样就不能保证只有一个对象被创建,且第二个创建的对象将第一个创建的对象覆盖
解决方法:
     1、懒汉模式
     调用对象时才产生实例对象
 
改进
     staticSingleton*GetInstance()
       {
              if(_sInstance ==NULL)//保证效率
              {
                     _mx.lock();//保证线程安全
                     if(_sInstance ==NULL)
                     {
                           _sInstance =newSingleton;
                           //解法:RAII 2.用库函数的guard
                     }
                     _mx.unlock();
              }
              return_sInstance;
       }
     新增static成员对象
     staticmutex_mx;
     在类外需要初始化
     mutexSingleton::_mx
    
     但是,这么做有会引入新的问题,即当发生new失败时,则会发生抛异常, 而抛异常则会导致死锁。
     解决方法:可以使用RAII,自动析构,guard
     staticSingleton*GetInstance()
       {
              if(_sInstance ==NULL)//保证效率
              {
                     lock_guard<mutex> lock(_mx);
                     if(_sInstance ==NULL)
                     {
                           _sInstance =newSingleton;//new 有可能会抛异常,若抛异常则导致死锁,但是用lock_guard可以出作用域自动析构
                     }
              }
              return_sInstance;
       }
     2、饿汉模式
     最开始就创建对象
     既线程安全,又高效
     指针为静态,在main函数之前初始化,
classSingleton
{
public:
       staticSingleton*GetInstance()
       {
              assert(_sInstance);
              
              return_sInstance;
       }
       voidprintf()
       {
              cout << _data << endl;
       }
protected:
       Singleton()
              :_data(0)
       {}
       //防拷贝,只申明不定义
       Singleton(Singleton&);
       Singleton&operator=(Singleton&);
       //指向实例的指针定义为静态私有,这样定义静态成员函数获取对象实例
       staticSingleton* _sInstance;
private:
       int_data;
};
Singleton*Singleton::_sInstance = new Singleton;

三、关于面试题
1、定义一个类,只能在堆上生成对象
     
classA
{
public:
       A*GetObj()
       {
              returnnewA;
       }
private:
       A()
       {}
       A(constA&);
};
2、定义一个类,只能在栈上生成对象
     
classA
{
private:
       void*operator new (size_t);
       voidoperator delete(void*p);
       void*operator new[](size_t);
       voidoperator delete[](void*p);
private:
       inta;
};
0 0