• 手把手教你实现buffer(一) —— C++中buffer的概念及需求


    写在前面

    buffer的概念很庞大,根据不同场景,有各种各样功能的buffer,比如双缓冲buffer,jitterbuffer。这篇文章说的buffer,是指一段用于存取数据的内存空间,这是最基础的buffer。然而就是这种最基础的buffer,在C++中标准库也没有提供很通用,完善的buffer类(-_-!)。

    这一系列文章,将参照webrtc中的CopyOnWriteBuffer,一步步介绍如何实现这样的buffer。

    buffer的实现

    静态分配

    在我们平常的开发中,当需要一个buffer时,最简单的方式就时直接定义个数组,如下代码:

    //128字节的数组
    uint8_t buffer[128]
    
    • 1
    • 2

    这种方式叫静态数组,空间分配在栈上,产生了一个固定128字节长度的buffer。长度值是预估,并不是根据程序运行时分配空间,而是编译器就确定了,所以会造成空间浪费。

    动态分配

    通过newmalloc动态分配一个buffer,这种方式的好处在程序运行时分配,不会造成空间浪费,坏处也很明显,就是需要手动管理buffer,不小心就会造成内存泄露。

    通过智能指针管理buffer

    到了C++11,有了unique_ptr后,可以用它来代替裸指针管理动态分配的内存,达到自动释放内存的目的

    //在超出作用域时,会自动释放
    std::unique_ptr <uint8_t[]> buffer(new uint8_t[128]);
    
    
    • 1
    • 2
    • 3

    但是这种buffer还是太原始(本质就是通过指针管理buffer):

    1. 容量固定,虽然是动态分配,但是再扩容就比较麻烦
    2. 缺少必要的接口,比如判断是buffer否为空,获取buffer中的数据长度等

    vector代替指针

    标准库中的vector可以作为buffer使用,它可以自动管理内存,自动扩容,提供了必要接口。

    #include 
    #include 
    int main() {
        std::vector<uint8_t> buffer;
        //代表一段数据
        uint8_t data1[3] = {1,2,3};
        buffer.assign(data1,data1+3);
        std::cout<<"size:"<<buffer.size()<<",capacity:"<<buffer.capacity()<<std::endl;
        //代表另外一段数据
        uint8_t data2[5] = {1,2,3,4,5};
        //会自动扩容
        buffer.assign(data2,data2+5);
        std::cout<<"size:"<<buffer.size()<<",capacity:"<<buffer.capacity()<<std::endl;
        
        for (auto i:buffer) {
            std::cout<<(uint32_t)i<<" ";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    上面的代码中在将data2放入buffer时,buffer会自动扩容。vector也提供了size()capaciy()等基本接口。通过vectordata()方法可以获取内部buffer的指针。

    vector作为buffer使用的局限

    vector满足了作为一个buffer的大部分要求,但是它的接口还是有局限,比如vector没提供添加一段数据方法,尽管有assgin方法,但它是往vector中copy一段数据,而非添加。

    实现自己的buffer

    上面描述了buffer的需求,概括起来有如下几点:

    1. 内存动态分配
    2. 自动管理内存
    3. 自动扩容
    4. 提供使用方便的接口

    vector满足了前三个需求。但是第4个最重要,毕竟简单,好用是最核心的需求。

  • 相关阅读:
    用类继承计算长方体体积
    Java流程控制
    MQTT协议
    卷积神经网络的基本操作,卷积神经网络理论基础
    【CSDN】创作区上传图片-粘贴/文件上传失败解决!
    创建数据库
    京东到家MySQL容器化,为何首选Docker而非K8S?
    前端vue学习笔记(1)
    德人合科技 | 天锐绿盾终端安全管理系统
    c++day1
  • 原文地址:https://blog.csdn.net/mo4776/article/details/126107614