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

一、带着问题,找思路

有这样一个需求,有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,即可下载。

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

百里杨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值