单件模式,如何灵活应付单例的生命周期。

开始复习设计模式,第一个,单件模式。
我想我要写的东西太长了,于是我打算说我解决了什么问题,基础足够的同学请自行补脑。

单件模式 为解决复杂系统 只需要一个实例 的问题。但是没有提在C++里面怎么解决内存自动释放的问题。
我相信大多数人首先想到的C++实现都单纯的类似这样:
class Singleton 

public
~Singleton(){} 
static Singleton* Instance() 

   if (_instance == NULL) 
  { 
   _instance =  new Singleton(); 
  } 
   return _instance; 

private
Singleton(){} 
static Singleton* _instance; 
}; 
Singleton* Singleton::_instance = NULL;

这个确实是单件模式了,但是它没有解决单例的生命周期问题,new出来的内存没有delete掉,那么这个对象的生命到底什么时候结束呢?
答案不是确定的,在不同的操作系统平台上又不同的情况。Unix下是进程消失时内存释放。

我们来解决这个问题 ,给它加一个清理器。嘿嘿!~~
为了更加通用,我打算用模板来实现,请看代码:

//  singleton.h
#ifndef __SINGLETON__
#define __SINGLETON__

#include 

template
class Singleton {
public:
     static T *instance(){
         if (_instance == nullptr) {  //clang++ c++11标准
            _instance =  new T;
             static Cleaner clr;   // 延迟单件模式的清理对象
             /*
              static Cleaner clr;这个声明,由于是静态成员,系统会在栈里分配内存,回收工作也就由系统自动完成了。
             
*/
        }
         return _instance;
    }
    
private:
    Singleton(){
    }
    Singleton( const Singleton &s){};
     void  operator=( const Singleton &rhs){};
     static T *_instance;
    
     class Cleaner { 
     public
        Cleaner(){
            std::cout<<"Singleton cleaner Construct"<         } 
        ~Cleaner(){
            std::cout<<"Singleton cleaner Deconstruct"<              if(Singleton::instance()) {
                delete Singleton::instance();
            }
        } 
    }; 
};
 
template T * Singleton::_instance = nullptr;
 
#endif

那么我们来使用一下:
#include 
#include "singleton.h"

typedef  class aClass{
     // 整个函数可以注释掉
public:
     void Print( const  char* str){ 
        std::cout << "aClass print:" << str;
        std::cout<<", my address is " <<  this << std::endl;
    }
    ~aClass(){
        std::cout<<"aClass Deonstruct"<// 可以注释
    }
    aClass(){
        std::cout<<"aClass Construct"<// 可以注释
    }
}aClass;

void
 f(){
    Singleton::instance()->Print("print 1"); 
    Singleton::instance()->Print("print 2");
}

int main(){
    f();
     return 0;
}
这样解决了单件模式自动释放的问题。
原理是什么呢?
在instance中, static Cleaner clr; 这个声明,由于是静态成员,系统会在栈里分配内存,回收工作也就由系统自动完成了。

有时候我们要考虑单件在整个软件系统中的释放顺序,因此,
如果您还有兴趣,我们可以看一下这个单例的释放究竟是在什么时候:
#include 
#include "singleton.h"

typedef  class aClass{
     // 整个函数可以注释掉
public:
     void Print( const  char* str){ 
        std::cout << "aClass print:" << str;
        std::cout<<", my address is " <<  this << std::endl;
    }
    ~aClass(){
        std::cout<<"aClass Deonstruct"<// 可以注释
    }
    aClass(){
        std::cout<<"aClass Construct"<// 可以注释
    }
}aClass;

void f(){
    Singleton::instance()->Print("print 1"); 
    Singleton::instance()->Print("print 2");
}

class bClass{
public:
    bClass(){
        std::cout<<"bClass Construct"<     }
    ~bClass(){
        std::cout<<"bClass Deconstruct"<     }
}globalObject;

class cClass{
public:
    cClass(){
        std::cout<<"cClass Construct"<     }
    ~cClass(){
        std::cout<<"cClass Deconstruct"<     }
};

int main(){
    cClass c;
    
    f();
    
    Singleton::instance()->Print("print 2");
    
     return 0;
}

根据在MAC下的控制台的输出结果:
clang++ -std=c++1y main.cpp && ./a.out
bClass Construct
cClass Construct
aClass Construct
Singleton cleaner construct
aClass print:print 1, my address is 0x7f923ac000e0
aClass print:print 2, my address is 0x7f923ac000e0
aClass print:print 2, my address is 0x7f923ac000e0
cClass Deconstruct
Singleton cleaner deconstruct
aClass Deonstruct
bClass Deconstruct

我们可以看出,这个单件模式的实例的释放时机为:在main退出之后,在全局对象析构之前。(也就是说它的释放时机是和系统的栈内存一样的。)

最后有人会问,你这个没有考虑多线程下的问题。
是的,不过这也简单,我们为instance函数添加互斥条件就可以了。多线程的例子,我在后面在写。

谢谢参观!

你可能感兴趣的:(QT)