C++实现单例模式的自动释放

 更新时间:2021年09月13日 11:49:27   作者:带着你的名字  
这篇文章主要为大家详细介绍了C++实现单例模式的自动释放,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

单例模式是为了确保某个类只能创建一个对象而设计的。当一个程序的某个类型只允许有一个实例的时候使用。

一般采用动态分配的方式来生成单例对象,这个时候C++程序员就需要考虑内存回收的问题了,所以为了避免在使用单例模式时忘记回收资源而造成内存泄漏的问题,在实现单例模式的时候就使其可以自动被回收。

不带自动释放的单例模式的实现与销毁

我们先来复习一下没有自动回收机制的单例模式的实现和销毁。

单例模式的实现:

  • 将构造函数私有化
  • 在类中定义一个静态的指向本类型的指针变量
  • 定义一个返回值为该类的指针的静态成员函数,在类的外部调用该函数,生成单例对象。

单例模式的销毁:

不能在析构函数中释放那个指向本类型的指针变量
需要用静态的成员函数回收指向本类型的指针变量,然后在类的外部调用该成员函数来销毁该单例对象。

单例模式的自动释放

主要思想是,利用C++栈对象消亡是会自动回收的特点,来自动回收分配在堆上的单例对象,可以通过四种方法:友元类、内部类+静态数据成员、atexit()函数、pthread_once()+atexit()来实现

废话不多说,直接上代码。

1.借助友元类

//利用友元类,实现单例模式的自动释放

#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();  //构造函数和析构函数都得是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{
    //用来实现单例的自动释放的类
    //应该保存在栈上,程序结束时自动回收单例的资源
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.借助内部类和静态数据成员

//利用内部类,实现单例模式的自动释放

#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();  //构造函数和析构函数都得是private
    ~Singleton();
    static Singleton *_pInstance;

private:
    //应该设计为私有类,避免类外的其他成员使用
    class AutoRelease{
        //用来实现单例的自动释放的内部类
        //应该保存在栈上,程序结束时自动回收单例的资源
    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,所以对象应该放在静态区
};

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;  //饱汉模式 */
//饱汉模式多线程时不安全,需要使用饿汉模式,在程序跑起来前就生成单例对象
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()函数

//利用atexit函数,实现单例模式的自动释放

#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();  //构造函数和析构函数都得是private
    ~Singleton();
    static Singleton *_pInstance;
};

Singleton *Singleton::getInstance(){
    if(_pInstance == nullptr){
        _pInstance = new Singleton();
        //注册destroy函数,在进程结束的时候执行,从而自动回收单例
        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函数

//利用pthread_once和atexit函数,实现单例模式的自动释放

#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();  //构造函数和析构函数都得是private
    ~Singleton();
    static pthread_once_t _once;
    static Singleton *_pInstance;
};

void Singleton::init(){
    //初始化单例,注册回收函数
    if(_pInstance == nullptr){
        _pInstance = new Singleton();
        atexit(Singleton::destroy);
    }
}

Singleton *Singleton::getInstance(){
    //执行pthread_once,保证在多线程的情况下创建单例对象的安全性
    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;
}

//由于已经使用了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;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 基于C语言模拟实现人生重开模拟器游戏

    基于C语言模拟实现人生重开模拟器游戏

    人生重开模拟器是前段时间非常火的一个小游戏,所以本文我们将一起学习使用c语言写一个简易版的人生重开模拟器,感兴趣的小伙伴可以了解下
    2024-02-02
  • C语言植物大战数据结构二叉树堆

    C语言植物大战数据结构二叉树堆

    这篇文章主要为大家介绍了C语言植物大战数据结构二叉树堆的图文示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • 如何使用C++获取指定的重载函数地址

    如何使用C++获取指定的重载函数地址

    重载函数是完全不同的几个函数,有不同的函数地址,下面这篇文章主要给大家介绍了关于如何使用C++获取指定的重载函数地址的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • C语言对于volatile与gcc优化的探究

    C语言对于volatile与gcc优化的探究

    这篇文章主要介绍了C语言对于volatile与gcc优化的探究,volatile是一个特征修饰符(type specifier) volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。这是百度百科的介绍,那编译器是具体是怎么优化的呢
    2023-02-02
  • C++命令行解析包gflags的使用教程

    C++命令行解析包gflags的使用教程

    这篇文章主要给大家介绍了关于C++命令行解析包gflags的使用教程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • 将字符串str1复制为字符串str2的三种解决方法

    将字符串str1复制为字符串str2的三种解决方法

    以下是对将字符串str1复制为字符串str2的三种解决方法进行了详细的介绍,需要的朋友可以过来参考下,希望对大家有所帮助
    2013-10-10
  • C++红黑树应用之手搓set和map

    C++红黑树应用之手搓set和map

    这篇文章主要为大家详细介绍了如何使用红黑树封装set和map,且必须保证两种数据结构复用同一棵红黑树,且满足set和map的性质,set的value不可被改变,而map的value可以被改变,需要的可以参考一下
    2023-03-03
  • 详解C语言中的自定义类型

    详解C语言中的自定义类型

    这篇文章主要为大家详细介绍了C语言中的四大自定义类型(结构体、位段、枚举和联合)的相关知识,文中的示例代码简洁易懂,需要的可以参考一下
    2023-07-07
  • C++输入输出操作符重载的深入分析

    C++输入输出操作符重载的深入分析

    本篇文章是对C++输入输出操作符重载进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C/C++实现字符串模糊匹配

    C/C++实现字符串模糊匹配

    本文分别给大家介绍了2个C++在Linux平台和windows平台下实现字符串模糊匹配的方法,基本的核心思想都是一样的,均是使用fnmatch函数,有需要的小伙伴可以参考下。
    2016-04-04

最新评论