您的位置:首页 > 其它

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

2014-05-11 12:44 169 查看
开始复习设计模式,第一个,单件模式。

我想我要写的东西太长了,于是我打算说我解决了什么问题,基础足够的同学请自行补脑。

单件模式为解决复杂系统只需要一个实例的问题。但是没有提在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 <iostream>

template<typename T>

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"<<std::endl;

}

~Cleaner(){

std::cout<<"Singleton cleaner Deconstruct"<<std::endl;

if(Singleton<T>::instance()) {

delete Singleton::instance();

}

}

};

};

template<typename T> T * Singleton<T>::_instance = nullptr;

#endif

那么我们来使用一下:

#include <iostream>

#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"<<std::endl; //可以注释

}

aClass(){

std::cout<<"aClass Construct"<<std::endl; //可以注释

}

}aClass;

void f(){

Singleton<aClass >::instance()->Print("print 1");

Singleton<aClass >::instance()->Print("print 2");

}

int main(){

f();

return 0;

}
这样解决了单件模式自动释放的问题。

原理是什么呢?

在instance中,static
Cleaner clr;这个声明,由于是静态成员,系统会在栈里分配内存,回收工作也就由系统自动完成了。

有时候我们要考虑单件在整个软件系统中的释放顺序,因此,

如果您还有兴趣,我们可以看一下这个单例的释放究竟是在什么时候:

#include <vector>

#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"<<std::endl; //可以注释

}

aClass(){

std::cout<<"aClass Construct"<<std::endl; //可以注释

}

}aClass;

void f(){

Singleton<aClass >::instance()->Print("print 1");

Singleton<aClass >::instance()->Print("print 2");

}

class bClass{

public:

bClass(){

std::cout<<"bClass Construct"<<std::endl;

}

~bClass(){

std::cout<<"bClass Deconstruct"<<std::endl;

}

}globalObject;

class cClass{

public:

cClass(){

std::cout<<"cClass Construct"<<std::endl;

}

~cClass(){

std::cout<<"cClass Deconstruct"<<std::endl;

}

};

int main(){

cClass c;

f();

Singleton<aClass >::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函数添加互斥条件就可以了。多线程的例子,我在后面在写。

谢谢参观!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: