【C++】单例模式中的析构函数
最近写完项⽬,正是⼀波总结的时候。项⽬中⽤到了⼤量的单例模式,然⽽本以为写的轻车熟路的代码,结果却问题重重,单例模式如何析构?单例模式中如何保证线程安全?如何加锁?锁要封装成单例类嘛?这个单例类构造出1个对象会不会有问题?阻塞住会不会后⾯上锁的功能⽆法正常使⽤?还是锁不⽤单例模式封装?构造锁的对象时加static??......
不测试不知道,⼀测试⼀堆问题需要解决,好,从头开始看。
--------------------------------------------------------------------------------------
如何写单例模式?
《设计模式》⼀书中给出了⼀种很不错的实现,定义⼀个单例类,使⽤类的私有静态指针变量指向类的唯⼀实例,并⽤⼀个公有的静态⽅法获取该实例。
随便⼀个项⽬中的单例模式的代码⽚段:
(看了很多博客才知道,原来这个叫:双检锁保证线程安全的懒汉式单例模式)
所谓双重检查加锁机制,指的是:并不是每次进⼊getInstance⽅法都需要同步,⽽是先不
同步,进⼊⽅法过后,先检查实例是否存在,如果不存在才进⼊下⾯的同步块,这是第⼀重
检查。进⼊同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建⼀个
实例,这是第⼆重检查。这样⼀来,就只需要同步⼀次了,从⽽减少了多次在同步情况下进
⾏判断所浪费的时间。
单例模式的特点总结起来就是:
1.构造函数放在私有 :这样外界就不可以访问构造函数,保证单个对象创建
2.私有的静态类指针指向类的唯⼀实例,在类外声明:static成员存放于内存中,静态数据成员被当作是类的成员,在类中只有⼀份;静态数据成员定义时要分配空间,所以不能在类声明中定义。应该在类外定义
3.共有的静态⽅法去获得访问实例:静态⽅法为类的全部服务。
class Server
{
public:
static Server* getServer(string ip,unsigned short port)
{
if(NULL == _instance)
{
pthread_mutex_lock(&mutex);
if(NULL == _instance)
{
_instance = new Server(ip,port);
}
pthread_mutex_unlock(&mutex);
}
return _instance;
}
public:
static pthread_mutex_t mutex;
private:
Server(string ip,unsigned short port)
{
pthread_mutex_init(&mutex,NULL);
}
static Server* _instance;
};
Server* Server::_instance = NULL;
pthread_mutex_t Server::mutex;
写完后,想起⼀句话:⼀个new对应⼀个delete。
于是我想当然的在函数中加了析构函数:如下:
~Server()
{
delete _instance;
}
程序运⾏时,崩溃,出现了core dump
那么我们分析⼀下,什么是析构函数,其作⽤是什么?
1、析构函数名是在类名前加以符号“~”。
2、析构函数没有参数、返回类型和修饰符。
3、⼀个类中⾄多有⼀个析构函数,如果程序员没有定义析构函数,那么系统会⾃动地加⼊⼀个析构函数。
4、不能显式地调⽤析构函数,⽽是由系统⾃动调⽤。(曾经我写了个程序exit函数,竟然主动调⽤析构,咳咳,真是。。。往事不堪回⾸。。。)
5.先构造的后析构,够构造的先析构.....(从⼤⼆念到毕业的⼀句话...)
析构函数什么时候被调⽤?
析构函数在下边3种情况时被调⽤:
1.对象⽣命周期结束,被销毁时;
2.delete指向对象的指针时,或delete指向对象的基类类型指针and其基类虚构函数是虚函数时;
3.对象i是对象o的成员,o的析构函数被调⽤时,对象i的析构函数也被调⽤
那么,就到问题了
~Server()
{
delete _instance;
}
析构函数中delete _instance;_instance为类的唯⼀对象的指针,
delete指向对象的指针时会调⽤析构函数,那么这句代码会调⽤~Server(),~Server中⼜要delete对象的指针,则陷⼊⽆限递归,程序崩溃。
解决⽅法:
程序在结束的时候,系统会⾃动析构所有的全局变量。事实上,系统也会析构所有的类的静态成员变量,就像这些静态成员也是全局变量⼀样。利 ⽤这个特征,我们可以在单例类中定义⼀个这样的静态成员变量,⽽它的唯⼀⼯作就是在析构函数中删除单例类的实例。如下⾯的代码中的Garbo类 (Garbo意为垃圾⼯⼈):
class Garbo //设置为私有防⽌外界访问
{
public:
~Garbo()//实际去析构new的单例对象
{
if(ServerL::_instance != NULL)
{
deleteServerL::_instance;
ServerL::_instance = NULL;
}
}
};
static Garbo garbo; //静态私有的嵌套类对象,防⽌被外界访问
最终这个单例模式的Server类为:
class Server
{
public:
static Server* getServer(string ip,unsigned short port) {
if(NULL == _instance)
{
pthread_mutex_lock(&mutex);
if(NULL == _instance)
{
_instance = new Server(ip,port);
}
pthread_mutex_unlock(&mutex);
}
return _instance;
}
public:
static pthread_mutex_t mutex;
private:
class Garbo //设置为私有防⽌外界访问
{
public:
~Garbo()//实际去析构new的单例对象
单例模式的几种实现方式{
if(ServerL::_instance != NULL)
{
deleteServerL::_instance;
ServerL::_instance = NULL;
}
}
};
static Garbo garbo;
private:
Server(string ip,unsigned short port)
{
pthread_mutex_init(&mutex,NULL);
}
static Server* _instance;
};
Server* Server::_instance = NULL;
pthread_mutex_t Server::mutex;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论