C++ Boost CircularBuffer算法超详细精讲

提要

库 Boost.CircularBuffer 提供了一个循环缓冲区,它是一个具有以下两个基本属性的容器:

  • 循环缓冲区的容量是恒定的,由您设置。当您调用成员函数(例如 push_back())时,容量不会自动更改。只有您可以更改循环缓冲区的容量。循环缓冲区的大小不能超过您设置的容量。
  • 尽管容量不变,但您可以随时调用 push_back() 将元素插入循环缓冲区。如果已达到最大大小并且循环缓冲区已满,则将覆盖元素。

当可用内存量有限并且您需要防止容器任意增长时,循环缓冲区是有意义的。另一个例子是连续数据流,随着新数据的可用,旧数据变得无关紧要。通过覆盖旧数据自动重用内存。

要使用 Boost.CircularBuffer 中的循环缓冲区,请包含头文件 boost/circular_buffer.hpp。此头文件定义类 boost::circular_buffer。

示例 16.1。使用 boost::circular_buffer

#include <boost/circular_buffer.hpp>
#include <iostream>
int main()
{
  typedef boost::circular_buffer<int> circular_buffer;
  circular_buffer cb{3};
  std::cout << cb.capacity() << '\n';
  std::cout << cb.size() << '\n';
  cb.push_back(0);
  cb.push_back(1);
  cb.push_back(2);
  std::cout << cb.size() << '\n';
  cb.push_back(3);
  cb.push_back(4);
  cb.push_back(5);
  std::cout << cb.size() << '\n';
  for (int i : cb)
    std::cout << i << '\n';
}

boost::circular_buffer 是一个模板,必须用类型实例化。例如,示例 16.1 中的循环缓冲区 cb 存储 int 类型的数字。

循环缓冲区的容量是在实例化类时指定的,而不是通过模板参数。 boost::circular_buffer 的默认构造函数创建一个容量为零的缓冲区。另一个构造函数可用于设置容量。在示例 16.1 中,缓冲区 cb 具有三个元素的容量。

可以通过调用 capacity() 来查询循环缓冲区的容量。在示例 16.1 中,capacity() 将返回 3。

容量不等于存储元素的数量。虽然 capacity() 的返回值是常数,但 size() 返回缓冲区中元素的数量,这可能不同。 size() 的返回值始终介于 0 和循环缓冲区的容量之间。

Example16.1

示例 16.1 在第一次调用 size() 时返回 0,因为缓冲区不包含任何数据。调用 push_back() 三次后,缓冲区包含三个元素,第二次调用 size() 将返回 3。再次调用 push_back() 不会导致缓冲区增长。这三个新数字会覆盖之前的三个数字。因此,size() 在第三次调用时会返回 3。

作为验证,存储的数字会在示例 16.1 的末尾写入标准输出。输出包含数字 3、4 和 5,因为先前存储的数字已被覆盖。

示例 16.2。 boost::circular_buffer 的各种成员函数

#include <boost/circular_buffer.hpp>
#include <iostream>
int main()
{
  typedef boost::circular_buffer<int> circular_buffer;
  circular_buffer cb{3};
  cb.push_back(0);
  cb.push_back(1);
  cb.push_back(2);
  cb.push_back(3);
  std::cout << std::boolalpha << cb.is_linearized() << '\n';
  circular_buffer::array_range ar1, ar2;
  ar1 = cb.array_one();
  ar2 = cb.array_two();
  std::cout << ar1.second << ";" << ar2.second << '\n';
  for (int i : cb)
    std::cout << i << '\n';
  cb.linearize();
  ar1 = cb.array_one();
  ar2 = cb.array_two();
  std::cout << ar1.second << ";" << ar2.second << '\n';
}

Example16.2

示例 16.2 使用了其他容器中不存在的成员函数 is_linearized()、array_one()、array_two() 和 linearize()。这些成员函数阐明了循环缓冲区的内部结构。

循环缓冲区本质上类似于 std::vector。因为开始和结束的定义很好,所以可以将向量视为传统的 C 数组。也就是说,内存是连续的,第一个和最后一个元素总是在最低和最高的内存地址。但是,循环缓冲区不提供这样的保证。

尽管谈论循环缓冲区的开始和结束可能听起来很奇怪,但它们确实存在。可以通过迭代器访问元素,并且 boost::circular_buffer 提供了成员函数,例如 begin() 和 end()。虽然使用迭代器时不需要关心开始和结束的位置,但使用常规指针访问元素时情况会变得有点复杂,除非你使用 is_linearized()、array_one()、array_two()、和线性化()。

如果循环缓冲区的开头位于最低内存地址,则成员函数 is_linearized() 返回 true。在这种情况下,缓冲区中的所有元素从头到尾连续存储在不断增加的内存地址中,并且可以像传统的 C 数组一样访问元素。

如果 is_linearized() 返回 false,则循环缓冲区的开头不在最低内存地址,示例 16.2 中就是这种情况。虽然前三个元素 0、1 和 2 完全按此顺序存储,但第四次调用 push_back() 将用数字 3 覆盖数字 0。因为 3 是调用 push_back() 添加的最后一个元素,它现在是循环缓冲区的新端。现在开始是编号为 1 的元素,它存储在下一个更高的内存地址。这意味着元素不再连续存储在不断增加的内存地址中。

如果循环缓冲区的末尾位于比开头低的内存地址,则可以通过两个传统的 C 数组访问元素。为了避免计算每个数组的位置和大小,boost::circular_buffer 提供了成员函数 array_one() 和 array_two()。

array_one() 和 array_two() 都返回一个 std::pair,其第一个元素是指向相应数组的指针,第二个元素是大小。 array_one() 访问循环缓冲区开头的数组,array_two() 访问缓冲区末尾的数组。

如果循环缓冲区被线性化并且 is_linearized() 返回 true,则也可以调用 array_two()。但是,由于缓冲区中只有一个数组,因此第二个数组不包含任何元素。

为了简化问题并将循环缓冲区视为传统的 C 数组,您可以通过调用 linearize() 强制重新排列元素。完成后,您可以使用 array_one() 访问所有存储的元素,而无需使用 array_two()。

Boost.CircularBuffer 提供了一个名为 boost::circular_buffer_space_optimized 的附加类。此类也在 boost/circular_buffer.hpp 中定义。尽管此类的使用方式与 boost::circular_buffer 相同,但它在实例化时不保留任何内存。相反,内存是在添加元素时动态分配的,直到达到容量为止。删除元素会相应地释放内存。 boost::circular_buffer_space_optimized 更有效地管理内存,因此在某些情况下可能是更好的选择。例如,如果您需要一个大容量的循环缓冲区,它可能是一个不错的选择,但您的程序并不总是使用完整的缓冲区。

到此这篇关于C++ Boost CircularBuffer算法超详细精讲的文章就介绍到这了,更多相关C++ Boost CircularBuffer内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ Boost Algorithm算法超详细精讲

    目录 一.说明Boost.Algorithm 二.示例 练习 一.说明Boost.Algorithm Boost.Algorithm 请注意,其他 Boost 库提供了许多算法.例如,您会在 Boost.StringAlgorithms 中找到处理字符串的算法. Boost.Algorithm 提供的算法不受特定类的约束,例如 std::string.与标准库中的算法一样,它们可以与任何容器一起使用. 二.示例 示例 29.1.使用 boost::algorithm::one_of_equal(

  • C++ Boost Graph算法超详细精讲

    Boost.Graph 中的算法类似于标准库中的算法——它们是通用的并且非常灵活.但是,并不总是很清楚应该如何使用它们. 示例 31.8.使用breadth_first_search() 从内到外访问点 #include <boost/graph/adjacency_list.hpp> #include <boost/graph/breadth_first_search.hpp> #include <boost/graph/named_function_params.hpp&

  • C++ Boost Bimap示例详细讲解

    目录 一.提要 二.示例 练习 一.提要 库 Boost.Bimap 基于 Boost.MultiIndex 并提供了一个无需先定义即可立即使用的容器.该容器类似于 std::map,但支持从任一侧查找值. Boost.Bimap 允许您根据访问地图的方式创建任意一侧都可以作为关键点的地图.当您访问左侧作为键时,右侧是值,反之亦然. 二.示例 Example13.1.Usingboost::bimap #include <boost/bimap.hpp> #include <string

  • C++ Boost.Range与Adapters库使用详解

    目录 一.说明 二.适配器 练习 一.说明 本节叙述关于Boost.Range和Adeptor两个内容. Boost.Range 是一个库,乍一看,它提供的算法类似于标准库提供的算法.例如,您会发现函数 boost::copy(),它的作用与 std::copy() 相同.但是, std::copy() 需要两个参数,而 boost::copy() 需要一个范围. 二.适配器 标准库提供了几种可以传递谓词的算法.例如,传递给 std::count_if() 的谓词确定计算哪些元素. Boost.

  • C++ Boost Heap使用实例详解

    目录 一.说明Boost.Heap 二.功能示例 一.说明Boost.Heap Boost.Heap 也可以称为 Boost.PriorityQueue,因为该库提供了几个优先级队列.但是,Boost.Heap 中的优先级队列与 std::priority_queue 不同,它支持更多功能. 二.功能示例 示例 17.1.使用 boost::heap::priority_queue #include <boost/heap/priority_queue.hpp> #include <io

  • C++ Boost MultiArray简化使用多维数组库

    目录 一.介绍Boost.MultiArray 二.示例 一.介绍Boost.MultiArray Boost.MultiArray Boost.MultiArray 是一个简化使用多维数组的库.最重要的优点是多维数组可以像标准库中的容器一样使用.例如,有一些成员函数,例如 begin() 和 end(),让您可以通过迭代器访问多维数组中的元素.迭代器比通常用于 C 数组的指针更易于使用,尤其是对于具有多个维度的数组. 二.示例 示例 19.1.带有 boost::multi_array 的一维

  • C++ Boost Intrusive库示例精讲

    目录 一.说明 二.示例 一.说明 Boost.Intrusive 是一个特别适合在高性能程序中使用的库.该库提供了创建侵入式容器的工具.这些容器替换了标准库中的已知容器.它们的缺点是它们不能像 std::list 或 std::set 那样容易使用.但它们有以下优点: 侵入式容器不会动态分配内存.对 push_back() 的调用不会导致使用 new 进行动态分配.这是侵入式容器可以提高性能的一个原因. 侵入式容器不会动态分配内存.对 push_bacIntrusive 容器的调用存储原始对象

  • C++ Boost CircularBuffer算法超详细精讲

    提要 库 Boost.CircularBuffer 提供了一个循环缓冲区,它是一个具有以下两个基本属性的容器: 循环缓冲区的容量是恒定的,由您设置.当您调用成员函数(例如 push_back())时,容量不会自动更改.只有您可以更改循环缓冲区的容量.循环缓冲区的大小不能超过您设置的容量. 尽管容量不变,但您可以随时调用 push_back() 将元素插入循环缓冲区.如果已达到最大大小并且循环缓冲区已满,则将覆盖元素. 当可用内存量有限并且您需要防止容器任意增长时,循环缓冲区是有意义的.另一个例子

  • C++可扩展性与多线程超详细精讲

    目录 一.可扩展性和多线程 二.线程示例 一.可扩展性和多线程 基于 Boost.Asio 之类的库开发程序与通常的 C++ 风格不同.可能需要更长时间才能返回的函数不再按顺序调用. Boost.Asio 不调用阻塞函数,而是启动异步操作.操作完成后应该调用的函数现在在相应的处理程序中调用.这种方法的缺点是顺序执行函数的物理分离,这会使代码更难理解. 诸如 Boost.Asio 之类的库通常用于实现更高的效率.无需等待操作完成,程序可以在其间执行其他任务.因此,可以启动多个同时执行的异步操作——

  • Java贪心算法超详细讲解

    目录 什么是贪心算法 通过场景理解算法 问题分析 总结 什么是贪心算法 在分析和求解某个问题时,在每一步的计算选择上都是最优的或者最好的,通过这种方式期望最终的计算的结果也是最优的.也就是说,算法通过先追求局部的最优解,从而寻求整体的最优解. 贪心算法的基本步骤: 1.首先定义问题,确定问题模型是不是适合使用贪心算法,即求解最值问题: 2.将求极值的问题进行拆解,然后对拆解后的每一个子问题进行求解,试图获得当前子问题的局部最优解: 3.所有子问题的局部最优解求解完成后,把这些局部最优解进行汇总合

  • Java超详细精讲数据结构之bfs与双端队列

    目录 一.bfs 二.双端队列 三.算法题 1.kotori和迷宫 2.小红找红点 3.小红玩数组 一.bfs bfs(广度优先搜索),类似二叉树的层序遍历,利用队列完成.一般用于求最短路. 图的最短路问题: 给定一个无向图,每条边的长度都是1.求1号点到x号点的最短距离. 顶点数n 边数为m q次询问 输入x 输出1到x的最短距离. 若1号点到x不连通,则输出-1 二.双端队列 双端队列的应用(区间翻转): 对于长度为n的数组,给定一个长度为m的区间,区间初始位置为a[1]到a[m]. 3种操

  • C++模板的特化超详细精讲

    目录 一.泛型编程 二.函数模板 2.1.函数模板的概念 2.2.函数模板的格式 2.3.函数模板的原理 2.4.函数模板的实例化 2.4.1.隐式实例化 2.4.2.显示实例化 三.类模板 3.1.类模板的定义格式 3.1.类模板的实例化 四.模板的特化 4.1.概念 4.2.函数模板特化步骤 4.3.类模板的特化 4.3.1.全特化 4.3.2.偏特化 一.泛型编程 我们前面已经学过函数的重载,实现了在函数名相同的情况下,实现不同的功能! 例如: void Swap(int& left, i

  • Java BOI与NIO超详细实例精讲

    目录 Java BIO 示例代码 Java NIO 代码解读 Java BIO 阻塞IO,每个客户端链接都需要一个独立的线程处理,客户端链接没关闭时,线程链接处于阻塞状态,直到客户端链接关闭 如果客户端链接没有读取到数据,链接就会一直阻塞住,造成资源浪费 示例代码 开发一个ServerSocket服务端,通过telnet链接发送信息 import java.io.IOException; import java.io.InputStream; import java.net.ServerSock

  • MySQL数据库索引order by排序精讲

    排序这个词,我的第一感觉是几乎所有App都有排序的地方,淘宝商品有按照购买时间的排序.B站的评论有按照热度排序的... 对于MySQL,一说到排序,你第一时间想到的是什么?关键字order by?order by的字段最好有索引?叶子结点已经是顺序的?还是说尽量不要在MySQL内部排序? 事情的起因 现在假设有一张用户的朋友表: CREATE TABLE `user` ( `id` int(10) AUTO_INCREMENT, `user_id` int(10), `friend_addr`

随机推荐