SmartBuffer-让你不再为共享与私有缓存处理逻辑费神

2023-10-30

一、带着问题,找思路

有这样一个需求,有3个算法类,我们分别称为TestAlgo1、TestAlgo2、TestAlgo3,每个算法可以设置使用buffer类型是共享或私有。

补充:

共享是指在同类型算法的多个实例中使用同一块buffer,比如若算法TestAlgo1指定为共享buffer,则TestAlgo1的三个实例xx,yy,zz,均使用一块buffer进行读写操作。

私有是指每个算法实例,均有自己的buffer。

我们应该怎么实现呢?
首先我们定义一个内存块buffer类:

class MemoryBlock
{
public:
    MemoryBlock(size_t size)
    {
        _ptr = new char[size];
        _size = size;
        std::cout << "alloc memory : " << this << std::endl;
    }

    ~MemoryBlock()
    {
        delete[] (char*)_ptr;
        _ptr = nullptr;
        std::cout << "free memory : " << this << std::endl;
    }

    void* ptr()
    {
        return _ptr;
    }

    size_t size()
    {
        return _size;
    }

private:
    void* _ptr;
    size_t _size;
};

然后定义TestAlgo1算法类,通过构造函数传入shared,设置其缓存方式。其他算法如法炮制。

class TestAlgo1
{
public:
    TestAlgo1(bool shared)
        : privateBuffer(nullptr)
    {
        refCount++;
        if (shared)
        {
            if (sharedBuffer == nullptr)
            {
                sharedBuffer = new MemoryBlock(20);
            }
        }
        else
        {
            privateBuffer = new MemoryBlock(20);
        }
    }

    ~TestAlgo1()
    {
        refCount--;
        if (sharedBuffer && refCount == 0)
        {// 其实最好应该是所有TestAlgo1实例释放后,
         // 再删除共享buffer
            delete sharedBuffer;
            sharedBuffer = nullptr;
        }
        if (privateBuffer)
        {
            delete privateBuffer;
            privateBuffer = nullptr;
        }
    }

    virtual void run()
    {
        MemoryBlock* buffer = nullptr;
        if (sharedBuffer)
            buffer = sharedBuffer;
        else
            buffer = privateBuffer;
            
        // 读写操作buffer
        void* ptr = buffer->ptr();
        size_t size = buffer->size();
        // ...
    }

private:
    static MemoryBlock* sharedBuffer;
    static int refCount;
    MemoryBlock* privateBuffer;
};
MemoryBlock* TestAlgo1::sharedBuffer = nullptr;
int TestAlgo1::refCount = 0;

这代码。。。,此时只能用一个表情代替内心的独白。

在这里插入图片描述

不行,要做一个有追求(代码实在是太丑了)的程序猿,一定有其他办法。

在这里插入图片描述

是不是可以在创建算法实例的上一层创建好buffer,然后分配给每个算法,这样是不是就可以让算法共享一个buffer了。试一试:

class Controller
{
public:
    Controller()
    {
        // 读取算法配置
        // 假设TestAlgo1、TestAlgo2为共享,
        // TestAlgo3私有
        
        TestAlgo1* algo1 = new TestAlgo1();
        algo1->setBuffer();
        
        TestAlgo2* algo2 = new TestAlgo2();
        algo2->setBuffer();
        
        TestAlgo1* algo3 = new TestAlgo3();
        algo3->setBuffer();
    }
    
private:
    static MemoryBlock* sharedBuffer1;
    static MemoryBlock* sharedBuffer2;
    MemoryBlock* privateBuffer3;
};

写到此处2个static,就明白了,压根没必要写下去了,上一把在各个算法中如法炮制,现在变成在Controller里面继续如法炮制了。。。
随着算法的数量增加,内存的管理如果放在算法的上一层次来做的话,管理成本很高。再次回到需要解决的问题上来,我们需要解决的是buffer的管理问题,而私有buffer属于每个算法实例,自然不用再说,共享buffer属于某个算法的所有实例,嗯?这个属性是不是和static成员变量很像,所有我们应该将buffer的管理限制在算法类内部实现,刚才试过上升了,那么我还可以试试buffer管理下降至算法类的成员变量、或者基类试试。基类很明显不行,因为放在基类中的话,那么所有算法都共享同一个buffer了,我们只希望buffer在一类算法中共享。那么只剩一条路了。读完上述的代码,是否已经发现存在大量类似代码了。

二、干货时间到SmartBuffer

我们可以使用模板将这部分代码封装起来,定义为智能缓存类SmartBuffer:

template <class VisitorT, class BufferT>
class SmartBuffer
{
public:
    template <typename... Args>
    SmartBuffer(bool shared, Args&&... args)
        : privateObj(nullptr)
    {
        if (shared)
        {
            refCount++;
            if (sharedObj == nullptr) // 若共享,则仅在第一次实例化时创建BufferT
            {
                sharedObj = new BufferT(std::forward<Args>(args)...);
            }
        }
        else
        {
            privateObj = new BufferT(std::forward<Args>(args)...);
        }
    }

    ~SmartBuffer()
    {
        if (privateObj)
        {
            delete privateObj;
            privateObj = nullptr;
        }
        else
        {
            refCount--;
            if (sharedObj && refCount == 0) // 若共享,则仅在最后一次析构时释放BufferT
            {
                delete sharedObj;
                sharedObj = nullptr;
            }
        }
    }

    BufferT* buffer()
    {
        if (privateObj)
        {
            return privateObj;
        }
        else
        {
            return sharedObj;
        }
    }

private:
    SmartBuffer(const SmartBuffer&) = delete;
    SmartBuffer& operator=(const SmartBuffer&) = delete;

private:
    static int refCount;    ///<实例化引用计数,用于释放sharedObj
    static BufferT* sharedObj;  ///<每个VisitorT实例均共享sharedObj
    BufferT* privateObj;    ///<私有BufferT
};

template <class VisitorT, class BufferT>
int SmartBuffer<VisitorT, BufferT>::refCount = 0; ///<必须放在头文件,否则编译报错

template <class VisitorT, class BufferT>
BufferT* SmartBuffer<VisitorT, BufferT>::sharedObj = nullptr; ///<必须放在头文件,否则编译报错

原理什么的就不说了,大家自己看,我已经测试过了,就当是个轮子吧。后面会放出代码地址,有需要的自取。

下面说一下轮子的功能与使用:

1. 构造函数SmartBuffer(bool shared, Args&&… args)

shared - true表示使用共享buffer,反之私有。
若共享buffer,则SmartBuffer第一次实例化时,会自动创建缓存,后续不会再创建。

args - 可变长度参数,用于创建内部缓存时,传递给构造函数MemoryBlock(size_t size),故args需要填一个参数。

2. 析构函数~SmartBuffer()

若共享buffer,则最后一个SmartBuffer实例被销毁时,会自动释放共享缓存。

3.BufferT* buffer()

获取缓存块地址,可以对缓存进行读写操作。

三、编写测试代码

下面看SmartBuffer类的使用。

TestAlgo1类:

class TestAlgo1
{
public:
    TestAlgo1(bool shared)
    {
        std::cout << "TestAlgo1()" << std::endl;
        buffer = new SmartBufferT(shared, 20);
    }

    virtual ~TestAlgo1()
    {
        std::cout << "~TestAlgo1()" << std::endl;
        delete buffer;
        buffer = nullptr;
    }

private:
    typedef SmartBuffer<TestAlgo1, MemoryBlock> SmartBufferT;
    SmartBufferT* buffer;
};

TestAlgo2类:

class TestAlgo2
{
public:
    TestAlgo2(bool shared)
    {
        std::cout << "TestAlgo2()" << std::endl;
        buffer = new SmartBufferT(shared, 20);
    }

    virtual ~TestAlgo2()
    {
        std::cout << "~TestAlgo2()" << std::endl;
        delete buffer;
        buffer = nullptr;
    }

private:
    typedef SmartBuffer<TestAlgo2, MemoryBlock> SmartBufferT;
    SmartBufferT* buffer;
};

TestAlgo3类:

class TestAlgo3
{
public:
    TestAlgo3(bool shared)
    {
        std::cout << "TestAlgo3()" << std::endl;
        buffer = new SmartBufferT(shared, 20);
    }

    virtual ~TestAlgo3()
    {
        std::cout << "~TestAlgo3()" << std::endl;
        delete buffer;
        buffer = nullptr;
    }

private:
    typedef SmartBuffer<TestAlgo3, MemoryBlock> SmartBufferT;
    SmartBufferT* buffer;
};

三个类基本就是改了个编号。

怎么样,现在代码是否已经变得犹如清新可爱的小姐姐一般
在这里插入图片描述

main.cpp中:

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    TestAlgo1* algo1_1 = new TestAlgo1(true);
    TestAlgo1* algo1_2 = new TestAlgo1(true);

    TestAlgo2* algo2_1 = new TestAlgo2(false);
    TestAlgo2* algo2_2 = new TestAlgo2(false);

    TestAlgo3* algo3_1 = new TestAlgo3(true);
    TestAlgo3* algo3_2 = new TestAlgo3(false);
    TestAlgo3* algo3_3 = new TestAlgo3(true);

    delete algo1_1;
    delete algo1_2;

    delete algo2_1;
    delete algo2_2;

    delete algo3_1;
    delete algo3_2;
    delete algo3_3;

    return a.exec();
}

运行结果:
在这里插入图片描述



若对你有帮助,欢迎点赞、收藏、评论,你的支持就是我的最大动力!!!

同时,阿超为大家准备了丰富的学习资料,欢迎关注公众号“超哥学编程”,即可领取。

本文涉及工程代码,公众号回复:07SmartBuffer,即可下载。

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SmartBuffer-让你不再为共享与私有缓存处理逻辑费神 的相关文章

  • 【C/C++】报错问题积累

    1 出现Deprecated declaration XXX give arg types c文件中 有没有参数的函数时 声明需要加void即 main c void fun main h void fun void
  • fastcgi的环境变量

    FCGI ROLE RESPONDER SCRIPT FILENAME scripts 5 cgi QUERY STRING aaa 11111111111111 bbb 2222222222222222 ccc 3333333333333
  • C++操作SQLite数据库

    准备工作 在使用C 操作SQLite之前 需要获得sqlite3 h sqlite3 lib sqlite3 dll 大家可以在 这里 下载 并将这3个文件导入VC 工程中 其中sqlite3 dll文件放到Debug文件夹里 SQLite
  • android通过JNI用C/C++创建本地文件

    通过jni在本地创建文件 1 在android studio创建基本的jni工程 并且在APP界面成功显示 Hello from C 不会的可以看android studio使用jni 2 在native lib cpp文件中创建文件 为了
  • C++ 中的虚函数及虚函数表

    C 中的虚函数及虚函数表 一 虚函数及虚函数表的定义 二 虚函数表指针和虚函数表的创建时机 三 虚函数实现多态的原理 一 虚函数及虚函数表的定义 虚函数 虚函数就是在基类中定义一个未实现的函数名 使用虚函数的核心目的就是通过基类访问派生类定
  • 多线程系列之——事件内核对象

    所有内核对象里面事件内核对象是最简单的一个 它包括一个使用计数 还有两个布尔值 一个布尔值用来表示事件是手动重置事件还是自动重置事件 另一个布尔值表示当前是否处于触发状态 当一个手动重置事件被触发的时候 所有等待该事件的线程都能变成调度状态
  • C语言pcre库的使用及验证IP地址的合法性

    PCRE是一个用C语言编写的正则表达式函数库 它十分易用 同时功能也很强大 性能超过了POSIX正则表达式库和一些经典的正则表达式库 在使用PCRE库时 首先肯定是需要安装pcre的 不过一般的系统都会有自带的PCRE库 不过如果想使用最新
  • c/c++入门教程 - 1.基础c/c++ - 1.0 Visual Studio 2019安装环境搭建

    推荐视频课程 https www bilibili com video BV1et411b73Z p 2 已投币三连 b站果然是个学习的网站 本来是想在linux环境下运行QT 于是先学了几个月linux嵌入式驱动开发 后来发现太底层了 与
  • 大端模式和小端模式转化

    在工作中遇到一个问题 数据是以大端模式存储的 而机器是小端模式 必须进行转换 否则使用时会出问题 一 定义 大端模式 Big Endian 数据的高字节 保存在内存的低地址中 数据的低字节 保存在内存的高地址中 小端模式 Little En
  • 【C++】VS code如何配置使用C++(手把手教学)

    博 主 米码收割机 技 能 C Python语言 公众号 测试开发自动化 获取源码 商业合作 荣 誉 阿里云博客专家博主 51CTO技术博主 专 注 专注主流机器人 人工智能等相关领域的开发 测试技术 VS code如何配置使用C 手把手教
  • 经典面试题之new和malloc的区别

    new和malloc的区别是C C 一道经典的面试题 我也遇到过几次 回答的都不是很好 今天特意整理了一下 0 属性 new delete是C 关键字 需要编译器支持 malloc free是库函数 需要头文件支持 1 参数 使用new操作
  • Lua和C++交互总结(很详细)

    出处 http blog csdn net shun fzll article details 39120965 一 lua堆栈 要理解lua和c 交互 首先要理解lua堆栈 简单来说 Lua和C c 语言通信的主要方法是一个无处不在的虚拟
  • dev-c++官网位置和源码/库位置

    1 http devpaks org 2 http www bloodshed net 3 http www bloodshed net dev 转载于 https www cnblogs com vilyLei articles 1812
  • 为何在新建STM工程中全局声明两个宏

    在uVision中新建STM32工程后 需要从STM32标准库中拷贝标准外设驱动到自己的工程目录中 此时需要在工程设置 gt C C 选项卡下的Define文本框中键入这两个全局宏定义 STM32F40 41xxx USE STDPERIP
  • floor(),ceil()函数

    地板 天花板函数 均包含在math h中 意思分别为 返回不大于形参的最小整数和不小于形参的最大整数 include
  • lua和测试(一)

    lua做为一门高级语言 在游戏产业运用到机会越来越多了 测试掌握几门脚本语言也有一定的重要性 以下对于lua组合输入做出一些引导 测试需要掌握的关于返回数值 主要用到布尔类 前言的指引 lua的语法比较简单和清晰 学过c语言的可以很好的掌握
  • 在聚会中常玩数七的游戏,七的倍数和带有七的数字都不能说,比如14,27,28。请找出1~100的不能说的数字。...

    利用ES5的filter高阶函数来实现 var arr 1 2 3 4 5 6 7 17 27 21 22 28 100 r arr filter function x return x 10 7 x 7 0 alert r 7 14 17
  • 【C++】运算符重载

    加号运算符重载 include
  • C++ 中 const 和 constexpr 关键字解析:常量、函数和指针

    很多 C 的初学者看到 const 这个关键字的第一反应都是一头雾水 主要是因为 const 可 以出现在很多的位置 以及后面加入的 constexpr 更是常常感到困惑 今天就为大家一一解释出现它们的含义和以及作用 const 关键字 c
  • C中的内存使用问题

    请帮忙 操作系统 Linux 其中 sleep 1000 中 此时 top 显示Linux任务 给我写了7 7 MEM使用 valgrind 未发现内存泄漏 我明白 写得正确 所有 malloc 结果都是 NULL 但是为什么这次 睡眠 我

随机推荐

  • PRT(Precomputed Radiance Transfer【2002】)原理实现

    声明 本文源自对Games202课程 作业2的总结 参考 手把手教你写GAMES202作业 GAMES202 作业2 Precomputed Radiance Transfer 球谐函数 GAMES 202 作业2 Games202课程 个
  • Apache Beam 模型

    背景 Apache Beam 是Google 开源的一个统一编程框架 它本身不是一个流式处理平台 而是提供了统一的编程模型 帮助用户创建自己的数据处理流水线 实现可以运行在任意执行引擎之上批处理和流式处理任务 它包含 一个可以涵盖批处理和流
  • C++工程实践经验

    1 C 工程实践经验谈 陈硕 giantchen gmail com 最后更新 2012 4 20 版权声明 本作品采用 Creative Commons 署名 非商业性使用 禁止演绎 3 0 Unported 许可 协议 cc by nc
  • DF标志和串移动指令(movsb/movsw)

    1 标志寄存器的第10位DF 方向标志位 在串处理指令中 控制每次操作后si di的增减 DF 0 每次操作后 si di增加 DF 1 每次操作后 si di减小 我们可以用汇编语法描述movsb的功能如下 mov es di byte
  • 读写分离(主从复制,Sharding-JDBC)

    目录 1 介绍 2 配置 2 1配置准备 2 2配置主库Master 2 3配置从库Slave 3 读写分离案例 3 1Sharding JDBC 3 2入门案例 1 介绍 MySQL主从复制是一个异步的复制过程 底层是基于MySQL数据库
  • 数控直流电压源的设计与制作【keil5 & AD20]

    目录 1 设计任务与要求 1 1 设计任务 1 2 设计要求 2 设计方案 2 1 系统方案设计 2 1 1 滤波电路 2 2 2 辅助电源电路 2 2 3 三端可调稳压电路 2 2 4 电压 电流采样电路 2 2 元器件选型 2 2 1电
  • 浅析数据库case when 用法

    背景 今天在做一个需求 大致就是根据卡的logo去匹配 卡片的主卡数量 附属卡数量 激活卡数量 未激活卡数量 销卡数量等 当时以为要写很多sql 后来问了下同事说可以用case when写一条sql就能搞定 当时那个开心啊就是这样的O O哈
  • YoloV8改进策略:SPD-Conv加入到YoloV8中,让小目标无处遁形

    摘要 SPD Conv是一种新的构建块 用于替代现有的CNN体系结构中的步长卷积和池化层 它由一个空间到深度 SPD 层和一个非步长卷积 Conv 层组成 空间到深度 SPD 层的作用是将输入特征图的每个空间维度降低到通道维度 同时保留通道
  • arxiv国内镜像——快速下载

    arXiv org是一个收录科学文献预印本的在线数据库 目前包含了超过50万篇文章 并且以每个月5000篇的速度增长着 目前 这个数据库包含 数学 物理 计算机 非线性科学 定量生物学 定量财务以及统计学几大分类 其最重要的特点就是 开放式
  • php结合验证码实现登陆,thinkPHP实现的验证码登录功能示例

    本文实例讲述了thinkPHP实现的验证码登录功能 分享给大家供大家参考 具体如下 使用thinkphp自带的验证 实现登录页面的账号密码 验证码的验证 namespace Admin Controller use Think Contro
  • hashmap的扩容机制

    1 hashmap扩容的代码实现 hashMap的扩容机制 final Node
  • springboot整合IJPay实现微信支付-V3---微信小程序

    前言 微信支付适用于许多场合 如小程序 网页支付 但微信支付相对于其他支付方式略显麻烦 我们使用IJpay框架进行整合 一 IJpay是什么 JPay 让支付触手可及 封装了微信支付 支付宝支付 银联支付常用的支付方式以及各种常用的接口 不
  • Flutter

    看到有不少人在用 CustomScrollView 我实在心痛 杀鸡焉用牛刀 好好看代码 一个小小的 Column 就能解决问题 class AddHeaderFooterListPageState extends State
  • OpenCV3特征提取与目标检测之HOG(一)——HOG的概述与原理

    1 HOG Histogram of Oriented Gradient 是方向梯度直方图的意思 是一种特性描述子 通过计算与统计图像局部区域的梯度方向直方图来构成特征 边缘是图像颜色剧变的区域 在一副图像中 局部目标的表象与形状能够被梯度
  • PDU+远控,企业如何应用工业级智能PDU远程赋能业务?

    在很多企业级业务场景下 如何保障相关业务设备的稳定供电非常重要 插座也就成为了这些业务体系中的核心基建 为了保证相关设备供电的稳定 并且实现高效的远程管理 很多企业级的业务场景会部署专业的智能PDU 而在众多智能PDU设备中 向日葵智能PD
  • AI实战:钉钉 AI 的魔法棒,“小二” 帮你打工

    钉钉作为企业办公领域巨头般的存在 市场规模远超企微和飞书 随着阿里 AI 大模型的能力提升 AI 能力也在慢慢嵌入到阿里各个产品生态中去 钉钉 AI 就是在这样的一个背景下产生的 官方网站 https workspace dingtalk
  • Web项目如何做单元测试

    你可能会用单元测试框架 python的unittest pytest Java的Junit testNG等 那么你会做单元测试么 当然了 这有什么难的 test demo py def inc x return x 1 def test a
  • 在WebStorm中使用Vue的v-bind,v-on等内置指令时报命名空间的错误

    报错详情 Namespace v bind is not bound Namespace v on is not bound 等 问题说明 出现这个错误不是代码本身的问题 而是 WebStorm 这个编辑器的问题 因为 WebStorm 不
  • B+ Tree

    B Tree 什么是B B 树的时间复杂度和高度 Insert 简单的insert 复杂的Insert Delete 简单的delete 复杂的delete 时间复杂度 什么是B B tree是平衡二叉树 每个节点包含k个元素 k的范围在
  • SmartBuffer-让你不再为共享与私有缓存处理逻辑费神

    一 带着问题 找思路 有这样一个需求 有3个算法类 我们分别称为TestAlgo1 TestAlgo2 TestAlgo3 每个算法可以设置使用buffer类型是共享或私有 补充 共享是指在同类型算法的多个实例中使用同一块buffer 比如