广告位联系
返回顶部
分享到

C++使用智能指针实现模板形式的单例类

C#教程 来源:转载 作者:秩名 发布时间:2021-06-15 09:22:40 人浏览
摘要

实现一个模板形式的单例类,对于任意类型的类经过Singleton的处理之后,都能获取一个单例对象,并且可以传递任意参数 并且还使用了智能指针,把生成的单例对象托管给智能指针,从而实现自动回收单例对象的资源 此外,如果需要一个放在静态成员区的对象供其他

实现一个模板形式的单例类,对于任意类型的类经过Singleton的处理之后,都能获取一个单例对象,并且可以传递任意参数

并且还使用了智能指针,把生成的单例对象托管给智能指针,从而实现自动回收单例对象的资源

此外,如果需要一个放在静态成员区的对象供其他类使用,又不希望修改原有的类的代码,这时候可以通过该模板套一层壳,形成单例对象。

头文件

template_singleton.hpp

#include <iostream>
#include <string>
#include <memory>

using std::cout;
using std::endl;
using std::string;
using std::shared_ptr;
using std::make_shared;

template <typename T> class Singleton;

class Point
{
    //由于构造和析构被设为私有,想使用单例模板创造对象,就应该把其设为友元
    template <typename T> friend class Singleton;
    
public:
    //把析构函数设为private之后,智能指针销毁时无法调用
    //所以析构应该设置为public,但是就算是共有的析构,由于是把单例对象的内容托管给了智能指针
    //通过智能指针显式的调用析构函数,也是无法回收单例对象的,所以,不影响单例模式的实现
    ~Point(){
        cout << "~Point()" << endl;
    }

    void show(){
        cout << "(" << _ix << ", " << _iy << ")" << endl;
    }

private:
    //单例模式,要把构造函数和析构函数设为私有
    Point(int x, int y) : _ix(x), _iy(y)
    {
        cout << "Point(int, int)" << endl;
    }
    /* ~Point(){ */
    /*     cout << "~Point()" << endl; */
    /* } */

private:
    int _ix;
    int _iy;
};

class Computer
{
    //由于构造和析构被设为私有,想使用单例模板创造对象,就应该把其设为友元
    template <typename T> friend class Singleton;

public:
    void show(){
        cout << "name: " << _name << "  price: " << _price << endl;
    }
    void reset(const string &newname, const int &newprice){
        _name = newname;
        _price = newprice;
    }
    
    //使用public的析构函数,不影响单例模式的实现
    ~Computer(){
        cout << "~Computer()" << endl;
    }

private:
    //单例模式,要把构造函数设为私有
    //使用模板生成单例对象的时候调用了make_shared函数,如果传入的是栈上的内容
    //make_shared函数会调用拷贝构造函数在堆上重新生成一个托管给智能指针的对象,
    //并把原先的对象销毁,所以会在make_shared里面执行一次析构函数
    /* Computer(const Computer &rhs){ */
    /*     cout << "拷贝构造函数" << endl; */
    /* } */
    Computer(const string &name, const int price)
        :_name(name), _price(price) 
    {
        cout << "Computer(const string &, const int &)" << endl;
    }
    /* ~Computer(){ */
    /*     cout << "~Computer()" << endl; */
    /* } */

private:
    string _name;
    int _price;
};

//模板形式的单例类(使用了智能指针),应该使用饱汉模式
template <typename T>
class Singleton
{
public:
    template <typename ...Args> 
        static shared_ptr<T> getInstance(Args... args){
            if(_pInstance == nullptr){
                //这里会直接调用相应的类型的构造函数,托管给智能指针,类型在实例化后确定
                /* //使用临时对象托管给智能指针的时候,由于临时对象分配在栈上, */
                /* //所以在make_shared内部会重新分配堆上的空间来保存其内容, */
                /* //会调用拷贝构造函数,并把临时对象销毁 */
                /* _pInstance = make_shared<T>(T(args...)); */

                //如果把一个分配在堆上的指针托管给智能指针,传入的指针就不会被销毁
                T *tmp = new T(args...);
                _pInstance = make_shared<T>(*tmp);
            }
            return _pInstance;
        }

private:
    //由于使用了模板,所以_pInstance实际上指向的是 T ,而非本类型,
    //所以并不会生成Singleton对象,而是直接生成相应的T对象
    //T在实例化之后才会确定,究竟是哪种类型,
    //所以Singleton的构造函数和析构函数并不会执行
    Singleton(){
        cout << "Singleton()" << endl;
    }

    ~Singleton(){
        cout << "~Singleton()" << endl;
    }

    static shared_ptr<T> _pInstance;  //单例模式的指针,指向唯一的实体
};

//由于类型在实例化是才会确定,所以使用饱汉模式
template <typename T>
shared_ptr<T> Singleton<T>::_pInstance = nullptr;

测试文件

test_template_singleton.cc

#include "template_singleton.hpp"
#include <stdio.h>

using std::cout;
using std::endl;
using std::cin;

void test(){
    shared_ptr<Computer> pc1 = Singleton<Computer>::getInstance("Xiaomi", 6666);
    cout << "pc1: ";
    pc1->show();

    shared_ptr<Computer> pc2 = Singleton<Computer>::getInstance("Xiaomi", 6666);
    cout << "pc1: ";
    pc1->show();
    cout << "pc2: ";
    pc2->show();

    pc2->reset("Huawei", 8888);
    cout << endl << "after pc2->reset()" << endl;
    cout << "pc1: ";
    pc1->show();
    cout << "pc2: ";
    pc2->show();
    cout << endl;

    shared_ptr<Point> pt3 = Singleton<Point>::getInstance(1, 2);
    shared_ptr<Point> pt4 = Singleton<Point>::getInstance(1, 2);

    cout << endl << "通过模板,可以生成不同类型的单例对象:" << endl;
    cout << "pt3: ";
    pt3->show();
    cout << "pt4: ";
    pt4->show();

    cout << endl << "使用了智能指针,不同对象指向的地址也一样:" << endl;
    printf("&pc1 = %p\n", &pc1);
    printf("&pc2 = %p\n", &pc2);
    printf("&pt3 = %p\n", &pt3);
    printf("&pt4 = %p\n\n", &pt4);
    printf("&(*pc1) = %p\n", &(*pc1));
    printf("&(*pc2) = %p\n", &(*pc2));
    printf("&(*pt3) = %p\n", &(*pt3));
    printf("&(*pt4) = %p\n\n", &(*pt4));

}

int main()
{
    test();
    return 0;
}

运行结果

Computer(const string &, const int &)
pc1: name: Xiaomi  price: 6666
pc1: name: Xiaomi  price: 6666
pc2: name: Xiaomi  price: 6666

after pc2->reset()
pc1: name: Huawei  price: 8888
pc2: name: Huawei  price: 8888

Point(int, int)

# 通过模板,可以生成不同类型的单例对象:
pt3: (1, 2)
pt4: (1, 2)

# 使用了智能指针,不同对象指向的地址也一样:
&pc1 = 0x7ffe83bbd390
&pc2 = 0x7ffe83bbd3a0
&pt3 = 0x7ffe83bbd3b0
&pt4 = 0x7ffe83bbd3c0

&(*pc1) = 0x55b750c7e300
&(*pc2) = 0x55b750c7e300
&(*pt3) = 0x55b750c7e360
&(*pt4) = 0x55b750c7e360

~Point()
~Computer()


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://blog.csdn.net/weixin_42565760/article/details/117841134
相关文章
  • WPF实现窗体亚克力效果的代码

    WPF实现窗体亚克力效果的代码
    WPF 窗体设置亚克力效果 框架使用大于等于.NET40。 Visual Studio 2022。 项目使用MIT开源许可协议。 WindowAcrylicBlur设置亚克力颜色。 Opacity设置透
  • C#非托管泄漏中HEAP_ENTRY的Size对不上解析

    C#非托管泄漏中HEAP_ENTRY的Size对不上解析
    一:背景 1. 讲故事 前段时间有位朋友在分析他的非托管泄漏时,发现NT堆的_HEAP_ENTRY的 Size 和!heap命令中的 Size 对不上,来咨询是怎么回事?
  • C#中ArrayList 类的使用介绍
    一:ArrayList 类简单说明 动态数组ArrayList类在System.Collecions的命名空间下,所以使用时要加入System.Collecions命名空间,而且ArrayList提供添加,
  • C#使用BinaryFormatter类、ISerializable接口、XmlSeriali

    C#使用BinaryFormatter类、ISerializable接口、XmlSeriali
    序列化是将对象转换成字节流的过程,反序列化是把字节流转换成对象的过程。对象一旦被序列化,就可以把对象状态保存到硬盘的某个位
  • C#序列化与反序列化集合对象并进行版本控制
    当涉及到跨进程甚至是跨域传输数据的时候,我们需要把对象序列化和反序列化。 首先可以使用Serializable特性。 1 2 3 4 5 6 7 8 9 10 11 12 13 14
  • C#事件中关于sender的用法解读

    C#事件中关于sender的用法解读
    C#事件sender的小用法 开WPF新坑了,看了WPF的炫酷界面,再看看winForm实在是有些惨不忍睹(逃)。后面会开始写一些短的学习笔记。 一、什么
  • 在C#程序中注入恶意DLL的方法

    在C#程序中注入恶意DLL的方法
    一、背景 前段时间在训练营上课的时候就有朋友提到一个问题,为什么 Windbg 附加到 C# 程序后,程序就处于中断状态了?它到底是如何实现
  • 基于C#实现一个简单的FTP操作工具
    实现功能 实现使用FTP上传、下载、重命名、刷新、删除功能 开发环境 开发工具: Visual Studio 2013 .NET Framework版本:4.5 实现代码 1 2 3 4 5 6 7
  • C#仿QQ实现简单的截图功能

    C#仿QQ实现简单的截图功能
    接上一篇写的截取电脑屏幕,我们在原来的基础上加一个选择区域的功能,实现自定义选择截图。 个人比较懒,上一篇的代码就不重新设计
  • C#实现线性查找算法的介绍
    线性查找,肯定是以线性的方式,在集合或数组中查找某个元素。 通过代码来理解线性查找 什么叫线性?还是在代码中体会吧。 首先需要一
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计