buffer的概念很庞大,根据不同场景,有各种各样功能的buffer,比如双缓冲buffer,jitterbuffer。这篇文章说的buffer,是指一段用于存取数据的内存空间,这是最基础的buffer。然而就是这种最基础的buffer,在C++中标准库也没有提供很通用,完善的buffer类(-_-!)。
这一系列文章,将参照webrtc中的CopyOnWriteBuffer
,一步步介绍如何实现这样的buffer。
在我们平常的开发中,当需要一个buffer时,最简单的方式就时直接定义个数组,如下代码:
//128字节的数组
uint8_t buffer[128]
这种方式叫静态数组,空间分配在栈上,产生了一个固定128字节长度的buffer。长度值是预估,并不是根据程序运行时分配空间,而是编译器就确定了,所以会造成空间浪费。
通过new
或malloc
动态分配一个buffer,这种方式的好处在程序运行时分配,不会造成空间浪费,坏处也很明显,就是需要手动管理buffer,不小心就会造成内存泄露。
到了C++11,有了unique_ptr
后,可以用它来代替裸指针管理动态分配的内存,达到自动释放内存的目的
//在超出作用域时,会自动释放
std::unique_ptr <uint8_t[]> buffer(new uint8_t[128]);
但是这种buffer还是太原始(本质就是通过指针管理buffer):
标准库中的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<<" ";
}
}
上面的代码中在将data2
放入buffer
时,buffer会自动扩容。vector
也提供了size()
,capaciy()
等基本接口。通过vector
的data()
方法可以获取内部buffer的指针。
vector
满足了作为一个buffer的大部分要求,但是它的接口还是有局限,比如vector
没提供添加一段数据方法,尽管有assgin
方法,但它是往vector
中copy一段数据,而非添加。
上面描述了buffer的需求,概括起来有如下几点:
vector
满足了前三个需求。但是第4个最重要,毕竟简单,好用是最核心的需求。