单例模式
单例模式是23种GOF
模式中最简单的设计模式之一,属于创建型模式,它提供了一种创建对象的方式, 确保只有单个对象被创建。这个设计模式主要目的是想在整个系统中只能出现类的一个实例,即一个类只有一个对象。
现步骤有如下三步:
- 将构造函数私有化
- 在类中定义一个静态的指向本类型的指针变量
- 定义一个返回值为类指针的静态成员函数
一、单例模式的手动释放:
//单例模式的要求:一个类只能创建一个对象
//不能是栈对象,不能是全局对象,只能是堆对象 栈对象、全局对象系统自动分配空间
//
//用途:全局唯一的资源,全局唯一变量
//字典库、词典库、网页库、日志系统记录日志的对象
class Singleton
{
public:
//静态成员函数可以在类外不创建类的对象而调用类中的函数
static Singleton *getInstance()
{
if(nullptr == _pInstance)
{
_pInstance = new Singleton();//类的内部访问构造函数
}
return _pInstance;
}
static void destroy()
{
if(_pInstance)
{
//delete的工作机制 1.调用析构函数 2.operator delete
delete _pInstance; //调用private中的析构函数
_pInstance = nullptr;
}
}
private:
//构造函数私有,不能在类的外面访问
Singleton()
{
cout << "Singleton()" << endl;
}
~Singleton() //析构函数放在private里面,只能类内调用
{
cout << "~singleton()" << endl;
}
private:
//仅是声明,没有定义
//static int *s1;
static Singleton *_pInstance; //静态成员函数需要静态的成员
};
//类外的定义才是给静态成员变量分配空间
// int *s1 = nullptr;
Singleton * Singleton::_pInstance = nullptr;//静态成员进行初始化
//Singleton gS1;//全局对象,error,不能让其编译通过,只能让构造函数私有
//Singleton gS2;//全局对象
int main()
{
//Singleton s1;//栈对象,error,不能让其编译通过,只能让构造函数私有
//Singleton s2;//栈对象
//Singleton *ps1 = new Singleton(); //堆对象。类的外面创建不行,构造函数为私有
Singleton *ps1 = Singleton::getInstance();
Singleton *ps2 = Singleton::getInstance();
cout << "ps1 = " << ps1 << endl
<< "ps2 = " << ps2 << endl;
//delete ps1; //new两次指向同一空间,delete两次的时候会出现两次析构函数
//delete ps2; //把放入private中,就只能类内调用了
Singleton::destory();
return 0;
}
结果:
Singleton()
0x55ef6d254e70
0x55ef6d254e70
~Singleton()
-
Singleton::getInstance(); //创建对象
-
singleton::destory(); //销毁对象
-
从整个进程来看,main函数结束,对象也就随程序的结束而销毁了,那还为什么要自己释放呢?
- 堆对象只new,不去delete的话,会造成内存泄漏。内存泄漏很有可能造成程序的崩溃,所以要进行释放。
- 如果没有自己释放,用内存检测工具进行检查的时候,就错误的认为单例模式需要进行释放
二、单例模式的自动释放:
- 要想自动释放,而不是手动的调用singleton::destory()函数来对对象进行释放,需要想一下什么函数可以自动调用,不需要人为的操作?
- 构造函数、析构函数是自动调用的。可以再定义一个类AutoRelease,在类AutoRelease的析构函数释放单例模式的对象(delete _pInstance),通过类AutoRelease的栈对象随着程序的结束而调用类AutoRelease的析构函数,从而释放单例模式的对象(delete _pInstance),进而使单例模式自动释放。
- 再定义的这个类要想访问单例模式的对象_pInstance,有两种方法:1.友元函数 2.内部类
1、再定义的类AutoRelease设为Singleton的友元函数
#include <iostream>
using std::cout;
using std::endl;
//1、友元实现单例对象的自动释放
class AutoRelease;
class Singleton
{
public:
friend AutoRelease;
static Singleton *getInstance()
{
if(_pInstance == nullptr)
{
_pInstance = new Singleton();
}
return _pInstance;
}
/* static void destroy() */
/* { */
/* if(_pInstance) */
/* { */
/* delete _pInstance; */
/* _pInstance = nullptr; */
/* } */
/* } */
private:
Singleton()
{
cout << "Singleton()" << endl;
}
~Singleton()
{
cout << "~Singleton()" << endl;
}
private:
static Singleton *_pInstance;
};
Singleton *Singleton::_pInstance = nullptr;
class AutoRelease
{
public:
AutoRelease()
{
cout << "AutoRelease()" << endl;
}
~AutoRelease()
{
if(Singleton::_pInstance)
{
cout << "~AutoRelease()" << endl;
//delete的工作机制 1.调用析构函数 2.operator delete
delete Singleton::_pInstance;
Singleton::_pInstance = nullptr;
}
}
};
void test()
{
Singleton *s1 = Singleton::getInstance();
Singleton *s2 = Singleton::getInstance();
cout << s1 << endl
<< s2 << endl;
/* Singleton::destroy(); */
AutoRelease ar; //通过栈对象ar的自动销毁,从而调用析构函数,进而自动释放单例对象
}
int main()
{
test();
return 0;
}
结果:
Singleton()
0x5597d5c0de70
0x5597d5c0de70
AutoRelease()
~AutoRelease()
~Singleton()
2、再定义的类AutoRelease嵌套在Singleton的里面
#include <iostream>
using std::cout;
using std::endl;
//2、内部类 + 静态成员 实现单例对象的自动释放
//为什么用静态成员? 往下看51行
class AutoRelease;
class Singleton
{
public:
static Singleton *getInstance()
{
if(_pInstance == nullptr)
{
_pInstance = new Singleton();
}
return _pInstance;
}
private:
Singleton()
{
cout << "Singleton()" << endl;
}
~Singleton()
{
cout << "~Singleton()" << endl;
}
private:
class AutoRelease
{
public:
AutoRelease()
{
cout << "AutoRelease()" << endl;
}
~AutoRelease()
{
if(Singleton::_pInstance)
{
cout << "~AutoRelease()" << endl;
//delete的工作机制 1.调用析构函数 2.operator delete
delete Singleton::_pInstance;
Singleton::_pInstance = nullptr;
}
}
};
private:
static Singleton *_pInstance;
/* AutoRelease _ar; */
//为什么是静态变量?
//因为不是静态变量的时候,_ar是_pInstance对象的成员,_pInstace的销毁才会使_ar销毁,
//但是由于_ar没有销毁,无法调用析构函数来销毁_pInstace,陷入了死循环
//AutoRelease()
//Singleton()
//0x562be2b9ae70
//0x562be2b9ae70
static AutoRelease _ar;
};
//静态变量的定义,不是指针的可以不用赋值。
Singleton::AutoRelease Singleton::_ar;
Singleton *Singleton::_pInstance = nullptr;
void test()
{
Singleton *s1 = Singleton::getInstance();
Singleton *s2 = Singleton::getInstance();
cout << s1 << endl
<< s2 << endl;
}
int main()
{
test();
return 0;
}
结果:
AutoRelease()
Singleton()
0x558fc3972280
0x558fc3972280
~AutoRelease()
~Singleton()
- 自动释放单例对象除了上面的两种办法外,还有两种办法: 3.利用atexit函数 4.利用pthread_once函数
3、利用atexit函数,这个函数的参数是传入一个函数,作用是把这个函数放到程序的最后,在结束之前运行
#include <iostream>
#include <stdlib.h>
using std::cout;
using std::endl;
//3、atexit + 饿汉模式
class Singleton
{
public:
static Singleton *getInstance()
{
//如果不是饿汉模式的话,对于多线程环境来讲,不安全
//多个线程能够都进来,可以创建多个对象(多个new Singleton()),可能只销毁一个对象
//会造成内存泄漏,有可能使程序崩溃
//造成这个效果的主要原因是:_pInstance最开始是nullptr,有可能多个线程都可以进来
if(_pInstance == nullptr)
{
_pInstance = new Singleton();
atexit(destroy);
}
return _pInstance;
}
static void destroy()
{
if(_pInstance)
{
delete _pInstance;
_pInstance = nullptr;
}
}
private:
Singleton()
{
cout << "Singleton()" << endl;
}
~Singleton()
{
cout << "~Singleton()" << endl;
}
private:
static Singleton *_pInstance;
};
/* Singleton *Singleton::_pInstance = nullptr; */ //饱汉模式or懒汉模式(上来不吃资源)
Singleton *Singleton::_pInstance = getInstance(); //饿汉模式(一上来就要吃资源)
void test()
{
Singleton *s1 = Singleton::getInstance();
Singleton *s2 = Singleton::getInstance();
cout << s1 << endl
<< s2 << endl;
/* Singleton::destroy(); */
}
int main()
{
test();
return 0;
}
结果:
Singleton()
0x55b8ca7bae70
0x55b8ca7bae70
~Singleton()
4、pthread_once函数和线程库有关, 编译时加 -lpthread
#include <iostream>
#include <pthread.h>
#include <stdlib.h>
using std::cout;
using std::endl;
//4、pthread_once只会执行一次 平台相关性的函数
// pthread_once_t once_control = PTHREAD_ONCE_INIT;
// int pthread_once(pthread_once_t *once_control, void (*init_routine) (void))
class Singleton
{
public:
static Singleton *getInstance()
{
pthread_once(&_once, init);
return _pInstance;
}
static void init()
{
_pInstance = new Singleton();
atexit(destroy);
}
static void destroy()
{
if(_pInstance)
{
delete _pInstance;
_pInstance = nullptr;
}
}
private:
Singleton()
{
cout << "Singleton()" << endl;
}
~Singleton()
{
cout << "~Singleton()" << endl;
}
private:
static Singleton *_pInstance;
static pthread_once_t _once;
};
Singleton *Singleton::_pInstance = nullptr; //饱汉模式or懒汉模式(上来不吃资源)
/* Singleton *Singleton::_pInstance = getInstance(); //饿汉模式(一上来就要吃资源) */
pthread_once_t Singleton::_once = PTHREAD_ONCE_INIT;
void test()
{
Singleton *s1 = Singleton::getInstance();
Singleton *s2 = Singleton::getInstance();
cout << s1 << endl
<< s2 << endl;
/* Singleton::destroy(); */
}
int main()
{
test();
return 0;
}
结果:
Singleton()
0x558a003cbe70
0x558a003cbe70
~Singleton()