C++實(shí)現(xiàn)單例模式的自動(dòng)釋放
單例模式是為了確保某個(gè)類只能創(chuàng)建一個(gè)對(duì)象而設(shè)計(jì)的。當(dāng)一個(gè)程序的某個(gè)類型只允許有一個(gè)實(shí)例的時(shí)候使用。
一般采用動(dòng)態(tài)分配的方式來生成單例對(duì)象,這個(gè)時(shí)候C++程序員就需要考慮內(nèi)存回收的問題了,所以為了避免在使用單例模式時(shí)忘記回收資源而造成內(nèi)存泄漏的問題,在實(shí)現(xiàn)單例模式的時(shí)候就使其可以自動(dòng)被回收。
不帶自動(dòng)釋放的單例模式的實(shí)現(xiàn)與銷毀
我們先來復(fù)習(xí)一下沒有自動(dòng)回收機(jī)制的單例模式的實(shí)現(xiàn)和銷毀。
單例模式的實(shí)現(xiàn):
- 將構(gòu)造函數(shù)私有化
- 在類中定義一個(gè)靜態(tài)的指向本類型的指針變量
- 定義一個(gè)返回值為該類的指針的靜態(tài)成員函數(shù),在類的外部調(diào)用該函數(shù),生成單例對(duì)象。
單例模式的銷毀:
不能在析構(gòu)函數(shù)中釋放那個(gè)指向本類型的指針變量
需要用靜態(tài)的成員函數(shù)回收指向本類型的指針變量,然后在類的外部調(diào)用該成員函數(shù)來銷毀該單例對(duì)象。
單例模式的自動(dòng)釋放
主要思想是,利用C++棧對(duì)象消亡是會(huì)自動(dòng)回收的特點(diǎn),來自動(dòng)回收分配在堆上的單例對(duì)象,可以通過四種方法:友元類、內(nèi)部類+靜態(tài)數(shù)據(jù)成員、atexit()函數(shù)、pthread_once()+atexit()來實(shí)現(xiàn)
廢話不多說,直接上代碼。
1.借助友元類
//利用友元類,實(shí)現(xiàn)單例模式的自動(dòng)釋放
#include <stdio.h>
#include <iostream>
using std::cout;
using std::endl;
using std::cin;
class AutoRelease;
class Singleton{
//單例模式的類
public:
static Singleton *getInstance();//返回單例指針
private:
friend class AutoRelease;
Singleton(); //構(gòu)造函數(shù)和析構(gòu)函數(shù)都得是private
~Singleton();
static Singleton *_pInstance;
};
Singleton *Singleton::getInstance(){
if(_pInstance == nullptr){
_pInstance = new Singleton();
}
return _pInstance;
}
Singleton::Singleton()
{
cout << "Singleton()" << endl;
}
Singleton::~Singleton(){
cout << "~Singleton()" << endl;
}
class AutoRelease{
//用來實(shí)現(xiàn)單例的自動(dòng)釋放的類
//應(yīng)該保存在棧上,程序結(jié)束時(shí)自動(dòng)回收單例的資源
public:
AutoRelease(){
cout << "AutoRelease()" << endl;
}
~AutoRelease(){
cout << "~AutoRelease()" << endl;
if(Singleton::_pInstance == nullptr){
return;
}
delete Singleton::_pInstance;
Singleton::_pInstance = nullptr;
}
};
Singleton *Singleton::_pInstance = nullptr; //飽漢模式
int main()
{
Singleton *s1 = Singleton::getInstance();
Singleton *s2 = Singleton::getInstance();
AutoRelease at;
printf("s1 = %p\n", s1);
printf("s2 = %p\n", s2);
s1 = nullptr;
s2 = nullptr;
return 0;
}
2.借助內(nèi)部類和靜態(tài)數(shù)據(jù)成員
//利用內(nèi)部類,實(shí)現(xiàn)單例模式的自動(dòng)釋放
#include <stdio.h>
#include <iostream>
using std::cout;
using std::endl;
using std::cin;
class Singleton{
//單例模式的類
public:
static Singleton *getInstance();//返回單例指針
private:
friend class AutoRelease;
Singleton(); //構(gòu)造函數(shù)和析構(gòu)函數(shù)都得是private
~Singleton();
static Singleton *_pInstance;
private:
//應(yīng)該設(shè)計(jì)為私有類,避免類外的其他成員使用
class AutoRelease{
//用來實(shí)現(xiàn)單例的自動(dòng)釋放的內(nèi)部類
//應(yīng)該保存在棧上,程序結(jié)束時(shí)自動(dòng)回收單例的資源
public:
AutoRelease(){
cout << "AutoRelease()" << endl;
}
~AutoRelease(){
cout << "~AutoRelease()" << endl;
if(Singleton::_pInstance == nullptr){
return;
}
delete Singleton::_pInstance;
Singleton::_pInstance = nullptr;
}
};
private:
static AutoRelease _at; //由于AutoRelease是private,所以對(duì)象應(yīng)該放在靜態(tài)區(qū)
};
Singleton *Singleton::getInstance(){
if(_pInstance == nullptr){
_pInstance = new Singleton();
}
return _pInstance;
}
Singleton::Singleton()
{
cout << "Singleton()" << endl;
}
Singleton::~Singleton(){
cout << "~Singleton()" << endl;
}
/* Singleton *Singleton::_pInstance = nullptr; //飽漢模式 */
//飽漢模式多線程時(shí)不安全,需要使用餓漢模式,在程序跑起來前就生成單例對(duì)象
Singleton *Singleton::_pInstance = Singleton::getInstance();//餓漢模式
Singleton::AutoRelease Singleton::_at;
int main()
{
Singleton *s1 = Singleton::getInstance();
Singleton *s2 = Singleton::getInstance();
printf("s1 = %p\n", s1);
printf("s2 = %p\n", s2);
s1 = nullptr;
s2 = nullptr;
return 0;
}
3.借助atexit()函數(shù)
//利用atexit函數(shù),實(shí)現(xiàn)單例模式的自動(dòng)釋放
#include <stdio.h>
#include <iostream>
using std::cout;
using std::endl;
using std::cin;
class Singleton{
//單例模式的類
public:
static Singleton *getInstance();//返回單例指針
static void destroy();
private:
friend class AutoRelease;
Singleton(); //構(gòu)造函數(shù)和析構(gòu)函數(shù)都得是private
~Singleton();
static Singleton *_pInstance;
};
Singleton *Singleton::getInstance(){
if(_pInstance == nullptr){
_pInstance = new Singleton();
//注冊(cè)destroy函數(shù),在進(jìn)程結(jié)束的時(shí)候執(zhí)行,從而自動(dòng)回收單例
atexit(Singleton::destroy);
}
return _pInstance;
}
void Singleton::destroy(){
if(Singleton::_pInstance == nullptr){
return;
}
delete Singleton::_pInstance;
Singleton::_pInstance = nullptr;
}
Singleton::Singleton()
{
cout << "Singleton()" << endl;
}
Singleton::~Singleton(){
cout << "~Singleton()" << endl;
}
//為了保證多線程情況下的安全性,使用餓漢模式
Singleton *Singleton::_pInstance = Singleton::getInstance(); //餓漢模式
int main()
{
Singleton *s1 = Singleton::getInstance();
Singleton *s2 = Singleton::getInstance();
printf("s1 = %p\n", s1);
printf("s2 = %p\n", s2);
s1 = nullptr;
s2 = nullptr;
return 0;
}
4.借助pthread_once和atexit函數(shù)
//利用pthread_once和atexit函數(shù),實(shí)現(xiàn)單例模式的自動(dòng)釋放
#include <stdio.h>
#include <iostream>
using std::cout;
using std::endl;
using std::cin;
class Singleton{
//單例模式的類
public:
static void init();
static Singleton *getInstance();//返回單例指針
static void destroy();
private:
friend class AutoRelease;
Singleton(); //構(gòu)造函數(shù)和析構(gòu)函數(shù)都得是private
~Singleton();
static pthread_once_t _once;
static Singleton *_pInstance;
};
void Singleton::init(){
//初始化單例,注冊(cè)回收函數(shù)
if(_pInstance == nullptr){
_pInstance = new Singleton();
atexit(Singleton::destroy);
}
}
Singleton *Singleton::getInstance(){
//執(zhí)行pthread_once,保證在多線程的情況下創(chuàng)建單例對(duì)象的安全性
pthread_once(&_once, init);
return _pInstance;
}
void Singleton::destroy(){
if(Singleton::_pInstance == nullptr){
return;
}
delete Singleton::_pInstance;
Singleton::_pInstance = nullptr;
}
Singleton::Singleton()
{
cout << "Singleton()" << endl;
}
Singleton::~Singleton(){
cout << "~Singleton()" << endl;
}
//由于已經(jīng)使用了pthread_once來保證安全性,所以使用飽漢模式即可
Singleton *Singleton::_pInstance = nullptr;
/* Singleton *Singleton::_pInstance = Singleton::getInstance(); //餓漢模式 */
pthread_once_t Singleton::_once = PTHREAD_ONCE_INIT;
int main()
{
Singleton *s1 = Singleton::getInstance();
Singleton *s2 = Singleton::getInstance();
printf("s1 = %p\n", s1);
printf("s2 = %p\n", s2);
s1 = nullptr;
s2 = nullptr;
return 0;
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
基于C語(yǔ)言模擬實(shí)現(xiàn)人生重開模擬器游戲
人生重開模擬器是前段時(shí)間非?;鸬囊粋€(gè)小游戲,所以本文我們將一起學(xué)習(xí)使用c語(yǔ)言寫一個(gè)簡(jiǎn)易版的人生重開模擬器,感興趣的小伙伴可以了解下2024-02-02
C語(yǔ)言植物大戰(zhàn)數(shù)據(jù)結(jié)構(gòu)二叉樹堆
這篇文章主要為大家介紹了C語(yǔ)言植物大戰(zhàn)數(shù)據(jù)結(jié)構(gòu)二叉樹堆的圖文示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
C語(yǔ)言對(duì)于volatile與gcc優(yōu)化的探究
這篇文章主要介紹了C語(yǔ)言對(duì)于volatile與gcc優(yōu)化的探究,volatile是一個(gè)特征修飾符(type specifier) volatile的作用是作為指令關(guān)鍵字,確保本條指令不會(huì)因編譯器的優(yōu)化而省略,且要求每次直接讀值。這是百度百科的介紹,那編譯器是具體是怎么優(yōu)化的呢2023-02-02

