单例模式

单例模式

单例模式是23种GOF模式中最简单的设计模式之一,属于创建型模式,它提供了一种创建对象的方式, 确保只有单个对象被创建。这个设计模式主要目的是想在整个系统中只能出现类的一个实例,即一个类只有一个对象

现步骤有如下三步:

  1. 将构造函数私有化
  2. 在类中定义一个静态的指向本类型的指针变量
  3. 定义一个返回值为类指针的静态成员函数

一、单例模式的手动释放:

//单例模式的要求:一个类只能创建一个对象
//不能是栈对象,不能是全局对象,只能是堆对象  栈对象、全局对象系统自动分配空间
//
//用途:全局唯一的资源,全局唯一变量
//字典库、词典库、网页库、日志系统记录日志的对象

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()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值