单例模式简析

一、单例模式
     单例模式确保一个类只有一个实例,自行提供这个实例并向整个系统提供这个实例。
     特点就是多读单写。
函数简单实现:
class Singleton
{
public :
        static Singleton *GetInstance() //申明为static,可以由对象直接调用,不用用类调用
       {
               if (_sInstance == NULL )
              {
                     _sInstance = new Singleton ;
              }
               return _sInstance;
       }
        void printf()
       {
              cout << _data << endl;
       }
protected :
       Singleton()
              :_data(0)
       {}
        //防拷贝,只申明不定义
       Singleton( Singleton &);
        Singleton &operator=( Singleton &);
        //指向实例的指针定义为静态私有,这样定义静态成员函数获取对象实例
        static Singleton * _sInstance;
private :
        int _data;
};
Singleton * Singleton ::_sInstance = NULL ; //初始化
int main()
{
        Singleton ::GetInstance()->printf();
        return 0;
}

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

三、关于面试题
1、定义一个类,只能在堆上生成对象
     
class A
{
public :
        A *GetObj()
       {
               return new A ;
       }
private :
       A()
       {}
       A( const A &);
};
2、定义一个类,只能在栈上生成对象
     
class A
{
private :
        void *operator new ( size_t );
        void operator delete( void *p);
        void *operator new[]( size_t );
        void operator delete[]( void *p);
private :
        int a;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值