STL之queue容器详解
文章目录1. queue概念2. queue成员函数2.1 queue示例程序3. queue应用场景4. queue源码5. queue如何有效清空内存空间6. queue线程安全吗?7. 总结1. queue概念 queue是一种提供FIFO(先进先出)行为的标准容器,它满足容器的大多数要求。本质它不是真正的容器,而是一个适配器。因为它并未定义与迭代器有关的任何内容及接口。它持有另..
文章目录
1. queue概念
queue是一种提供FIFO(先进先出)行为的标准容器,它满足容器的大多数要求。本质它不是真正的容器,而是一个适配器。因为它并未定义与迭代器有关的任何内容及接口。它持有另一个容器,并为该容器提供包装器接口。包装器强制执行严格的先进先出队列行为。第二个模板参数定义了底层序列/容器的类型。它的默认值是std::deque,但是它可以是任何支持 front、 back、push_back和 pop_front的类型,比如std::list或适当的用户定义类型。queue的定义可以参见 stl_queue.h 。即:template <class T,class Container = deque <T>> class queue;
图1 queue容器示意图
当size() = 0时候,empty()为true。
2. queue成员函数
·empty() 判断queue容器是否为空
·size() 返回当前queue容器的大小(既有多少元数据)
·front() 访问queue容器的第一个(首部)元素
·back() 访问queue容器的(尾部)最后一个元数据
·push() 向queue容器中插入新的元数据
·emplace() 构造并插入元数据
·pop() 删除下一个元数据
·swap() 交互两个queue容器的内容
2.1 queue示例程序
该示例程序演示了queue队列中各成员函数的使用规则。
queue<int> qList; //1. 创建一个空的queue队列
queue<int> bList;
for(int i = 0; i < 10; ++i)
{
qList.push(i + 1); //2. 向队列qList中插入10个元数据
}
cout<<"--------------------------------------"<<endl;
//3. 输出qLis队列的大小,共包含了10个元数据
cout<<"qList size: "<<qList.size()<<endl;
//4. 判断qList队列是否为空, 若为空--true(1), 不为空--false(0)
cout<<"qList empty: "<<qList.empty()<<endl;
//5. 输出qList队列的所有元数据,前提条件是当其不为空时
while(!qList.empty())
{
//6. 输出qList队列的第一个(队首)元素
cout<<qList.front()<<" ";
//7. 将队首元数据从当前qList队列中移除掉(删除)
qList.pop();
}
cout<<endl;
cout<<"--------------------------------------"<<endl;
//8. 再次打印队列qList的大小, 因为前面已经全部移除掉,因此这里大小是0
cout<<"qList size(2): "<<qList.size()<<endl;
//9. bList队列采用默认初始化,因此没有元数据,其大小为0
cout<<"bList size: "<<bList.size()<<endl;
//10.bList队列为空
cout<<"bList empty: "<<bList.empty()<<endl;
cout<<"--------------------------------------"<<endl;
//11. 构造数据向qList中插入数字1,3,5
qList.emplace(1);
qList.emplace(3);
qList.emplace(5);
//12. 交换两个容器的数据,此后,qList大小为0, 则bList队列大小为3.
bList.swap(qList);
//13. bList队列大小为3
cout<<"bList size: "<<bList.size()<<endl;
//14. bList容器有3个元数据,因此,不为空=0
cout<<"bList empty: "<<bList.empty()<<endl;
cout<<"--------------------------------------"<<endl;
while(!bList.empty())
{
cout<<bList.front()<<" ";
bList.pop();
}
cout<<endl;
cout<<"--------------------------------------"<<endl;
该示例程序的输出结果是:
--------------------------------------
qList size: 10
qList empty: 0
1 2 3 4 5 6 7 8 9 10
--------------------------------------
qList size(2): 0
bList size: 0
bList empty: 1
--------------------------------------
bList size: 3
bList empty: 0
--------------------------------------
1 3 5
--------------------------------------
3. queue应用场景
队列queue的底层实现采用的deque。关于queue队列,它的主要特性是FIFO(先进先出),结合它的内部结构和功能特征分析,队列queue适合用来做“异步处理、应用解耦、流量削峰、日志处理和消息通讯”,项目中用的最多的是生产者、消费者模式,将非核心流程异步化,提高系统响应性能。比如某线程从kafka消费出来的批量数据它只需要将其放到某个缓存队列中,然后有后台线程专门负责从该缓存队列里面取数据进行相应处理,是入库?还是其他义无逻辑处理,对消费kafka数据的线程来说,它并不关心,也无需等待底层义务处理情况。这样的异步处理设计具有弱耦合性,提供系统性能。
图来自 shilod
4. queue源码
4.1 如何获取queue源码
如果希望对STL(标准模板库)有着更深的理解和认识,最好的方法就是先熟悉理论知识,知道顺序容器、关联容器都分别有哪些,然后每个容器的优缺点,或说是特性。然后源码阅读,理论联系实际,这样对STL的掌握和见解有着更深一层的提高。首先STL仅是一个C++标准里规定的接口规范,并没有具体实现,因此每个平台上面的编译器都会有着自己的STL的实现。如何获取STL相关源码?你可以参考知乎的这篇博客 这么多款STL,总有一款适合你 。介绍挺详细的,很具有参考意义。
我阅读的是GNU/gcc-9.1.0编译器下的STL源码, Index of /gnu/gcc 中列出了历代(v1.42~v9.3.0)gcc编译器的版本下载列表。根据自己需要选择下载对应版本。
4.2 关于queue实现
5. queue如何有效清空内存空间
从上面2.1小节中示例代码可看到,删除queue队列中元数据的方式是使用成员函数pop() 。即一直不断循环删除队列头中的元数据,直到该queue队列为空为止。常规写法如下:
queue<int> qList;
while(!qList.empty()) qList.pop(); //移除queue队列首部元数据,直到为空
除此方法外,有没有一种不需判断N次(即队列有N个元素据)即可达到删除队列中全部元数据的方法?这个在stackoverflow上面有一篇专门讨论该话题的文章 如何有效清除std::queue? 。
实例化一个临时的空队列与其进行交换,即:queue<int>().swap(qList);
备注:swap函数好像在C++11的queue中才有该成员函数。
也可以直接将其赋值为空。queue<int> qList; qList = {};
。对于这几种删除queue队列元数据的方法,在其效率上我没有去实测过,具体哪一种高效,还需以实测结果为准。
I found that swapping in C++03 version works 70-80% slower than assignment to an empty object. In C++11 there is no difference in performance
6. queue线程安全吗?
在4.1节中提到过STL仅是C++提供的一套接口规范,每个编译器厂商的具体实现都有可能不同,因此C++本身是不提供任何关于STL中各容器的线程安全问题的方案的。这个需要STL库使用者自己去保证。cplusplus.cm 中也有专门的一节话题来讨论关于 STL thread safety 问题。下面我们写一个demo来测试下当多个(两个)线程往queue读,一个队里向里面写的时候,是否会出现异常。
7. 总结
更多推荐
所有评论(0)