C++ STL流缓冲区迭代器(streambuf_iterator)

C++ STL流迭代器》一节中,讲解了输入流迭代器和输出迭代器的功能和用法,在此基础上,本节继续讲解输入流缓冲区迭代器。

在学习本节之前,读者有必要先了解什么是缓冲区,可阅读《进入缓冲区(缓存)的世界》一节做详细了解。

我们知道在 C++ STL 标准库中,流迭代器又细分为输入流迭代器和输出流迭代器,流缓冲区迭代器也是如此,其又被细分为输入流缓冲区迭代器和输出流缓冲区迭代器:
  • 输入流缓冲区迭代器(istreambuf_iterator):从输入流缓冲区中读取字符元素;
  • 输出流缓冲区迭代器(ostreambuf_iterator):将连续的字符元素写入到输出缓冲区中。

流缓冲区迭代器和流迭代器最大的区别在于,前者仅仅会将元素以字符的形式(包括 char、wchar_t、char16_t 及 char32_t 等)读或者写到流缓冲区中,由于不会涉及数据类型的转换,读写数据的速度比后者要快。

接下来,将一一对它们的功能和用法做讲解。

C++ STL输入流缓冲区迭代器(istreambuf_iterator)

istreambuf_iterator 输入流缓冲区迭代器的功能是从指定的流缓冲区中读取字符元素。

值得一提的是,该类型迭代器本质是一个输入迭代器,即假设 p 是一个输入流迭代器,则其只能进行 ++p、p++、*p 操作,同时迭代器之间也只能使用 == 和 != 运算符。

另外,实现该类型迭代器的模板类也定义在<iterator>头文件,并位于 std 命名空间中。因此,在创建并使用该类型迭代器之前,程序中应包含如下代码:
#include <iterator>
using namespace std;

第二行代码不是必需的,但如果不用,则程序中在创建该类型的迭代器时,必须手动注明 std 命名空间(强烈建议初学者使用)。

创建输入流缓冲区迭代器的常用方式,有以下 2 种:
1) 通过调用 istreambuf_iterator 模板类中的默认构造函数,可以创建一个表示结尾的输入流缓冲区迭代器。要知道,当我们从流缓冲区中不断读取数据时,总有读取完成的那一刻,这一刻就可以用此方式构建的流缓冲区迭代器表示。

举个例子:
std::istreambuf_iterator<char> end_in;
其中,<> 尖括号中用于指定从流缓冲区中读取的字符类型。

2) 当然,我们还可以指定要读取的流缓冲区,比如:
std::istreambuf_iterator<char> in{ std::cin };
除此之外,还可以传入流缓冲区的地址,比如:
std::istreambuf_iterator<char> in {std::cin.rdbuf()};
其中,rdbuf() 函数的功能是获取指定流缓冲区的地址。

无论是传入流缓冲区,还是传入其地址,它们最终构造的输入流缓冲区迭代器是一样的。


下面程序演示了输入流缓冲区迭代器的用法:
#include <iostream>     // std::cin, std::cout
#include <iterator>     // std::istreambuf_iterator
#include <string>       // std::string
using namespace std;
int main() {
    //创建结束流缓冲区迭代器
    istreambuf_iterator<char> eos;
    //创建一个从输入缓冲区读取字符元素的迭代器
    istreambuf_iterator<char> iit(cin);
    string mystring;

    cout << "向缓冲区输入元素:\n";
    //不断从缓冲区读取数据,直到读取到 EOF 流结束符
    while (iit != eos) {
        mystring += *iit++;
    }
    cout << "string:" << mystring;
    return 0;
}
程序执行结果为:

向缓冲区输入元素:
abc ↙
^Z ↙
string:
abc

注意,只有读取到 EOF 流结束符时,程序中的 iit 才会和 eos 相等。在 Windows 平台上,使用 Ctrl+Z 组合键输入 ^Z 表示 EOF 流结束符,此结束符需要单独输入,或者输入换行符之后再输入才有效。

C++ STL输出流缓冲区迭代器(ostreambuf_iterator)

和 istreambuf_iterator 输入流缓冲区迭代器恰恰相反,ostreambuf_iterator 输出流缓冲区迭代器用于将字符元素写入到指定的流缓冲区中。

实际上,该类型迭代器本质上是一个输出迭代器,这意味着假设 p 为一个输出迭代器,则它仅能执行 ++p、p++、*p=t 以及 *p++=t 操作。

另外,和 ostream_iterator 输出流迭代器一样,istreambuf_iterator 迭代器底层也是通过重载赋值(=)运算符实现的。换句话说,即通过赋值运算符,每个赋值给输出流缓冲区迭代器的字符元素,都会被写入到指定的流缓冲区中。

需要指出的是,istreambuf_iterator 类模板也定义在<iterator>头文件,并位于 std 命名空间中,因此使用该类型迭代器,程序中需要包含以下代码:
#include <iterator>
using namespace std;

在此基础上,创建输出流缓冲区迭代器的常用方式有以下 2 种:
1) 通过传递一个流缓冲区对象,即可创建一个输出流缓冲区迭代器,比如:
std::ostreambuf_iterator<char> out_it (std::cout);
同样,尖括号 <> 中用于指定要写入字符的类型,可以是 char、wchar_t、char16_t 以及 char32_t 等。

2) 还可以借助 rdbuf(),传递一个流缓冲区的地址,也可以成功创建输出流缓冲区迭代器:
std::ostreambuf_iterator<char> out_it (std::cout.rdbuf());

下面程序演示了输出流缓冲区迭代器的用法:
#include <iostream>     // std::cin, std::cout
#include <iterator>     // std::ostreambuf_iterator
#include <string>       // std::string
#include <algorithm>    // std::copy

int main() {
    //创建一个和输出流缓冲区相关联的迭代器
    std::ostreambuf_iterator<char> out_it(std::cout); // stdout iterator
    //向输出流缓冲区中写入字符元素
    *out_it = 'S';
    *out_it = 'T';
    *out_it = 'L';

    //和 copy() 函数连用
    std::string mystring("\nhttp://c.biancheng.net/stl/");
    //将 mystring 中的字符串全部写入到输出流缓冲区中
    std::copy(mystring.begin(), mystring.end(), out_it);
    return 0;
}
程序执行结果为:

STL
http://c.biancheng.net/stl/

有关 copy() 函数的具体用法,后续章节会做详细讲解。


推荐文章
C语言typedef的用法详解

structstustu1; STUstu1;typedef typedef oldName newName; typedefintINTEGER; INTEGERa,b; a=1; b=2

如何选择数据库?

总体从5个方面平衡自己的需求:(1)标的(2)功能(3)多少人用(并发问题)(4)安全和稳定性(5)所用的操作系统(UNIX、linux、windows)对于用过的数据库有:  •dBase/FoxB

jQuery this事件

我们都知道,原生JavaScript中的this是非常复杂的。不过在jQuery中,this的使用相对来说简单一点。jQuery中的this大多数是用于事件操作中。 对于jQuery中的this,我

PHP清除、删除Session

当使用完一个Session变量后,可以将其删除;当完成一个会话后,也可以将其销毁。如果用户想退出Web系统,就需要为他提供一个注销的功能,把他的所有信息在服务器中销毁。 删除Session会话的方法

jQuery css()方法的用法

样式操作,指的是使用jQuery来操作一个元素的CSS属性。 在jQuery中,对于样式操作共有以下3种: CSS属性操作; CSS类名操作; 个别样式操作。 在jQuery中,CSS属

webtoon是什么意思啊?

webtoon是韩国的网络术语,网页版动漫、卡通的意思。webtoon是网页(web)和卡通(cartoon)的合成语,是用各种网络多媒体工具制作而成的网络漫画。不是单纯的在网页上提供漫画书浏览,是利

Zookeeper是什么?

ZooKeeper是一个高性能、集中化、分布式应用程序协调服务,主要是用来解决分布式应用中用户经常遇到的一些数据管理问题,例如,数据发布/订阅、命名服务、分布式协调通知、集群管理、Master选举、分

C++ STL begin()和end()函数用法

在前面章节中,我们已经对C++STL标准库提供的所有容器做了系统的讲解。读者可能已经注意到,无论是序列式容器还是关联式容器(包括哈希容器),不仅模板类内部提供有begin()和end()成员方法,C+

Java System类详解

System类位于java.lang包,代表当前Java程序的运行平台,系统级的很多属性和控制方法都放置在该类的内部。由于该类的构造方法是private的,所以无法创建该类的对象,也就是无法实例化该类

Python包及其定义和引用详解

对于一个需要实际应用的模块而言,往往会具有很多程序单元,包括变量、函数和类等,如果将整个模块的所有内容都定义在同一个Python源文件中,这个文件将会变得非常庞大,显然并不利于模块化开发。 什么是包

jpeg是一种什么格式?

JPEG(JointPhotographicExpertsGroup)是JPEG标准的产物,是面向连续色调静止图像的一种压缩标准。JPEG格式是最常用的图像文件格式,后缀名为.jpg或.jpeg。JP

C++ Boost库是什么?

Boost是一个功能强大、构造精巧、跨平台、开源并且完全免费的C++程序库。 1998年,BemanG.Dawes(C++标准委员会成员之一)发起倡议并建立了Boost社区,其目的是向C++程序员提

Linux工作管理简介(通俗易懂)

工作管理指的是在单个登录终端(也就是登录的Shell界面)同时管理多个工作的行为。也就是说,我们登陆了一个终端,已经在执行一个操作,那么是否可以在不关闭当前操作的情况下执行其他操作呢? 当然可以,我

C++11 constexpr和const的区别详解

《C++11constexpr》一节中,详细讲解了constexpr关键字的功能和用法。一些读者在学习过程中,经常会把const和constexpr搞混,不知道什么时候用const,什么时候用cons

利用面向对象思想实现搜索引擎

要想实现一个搜索引擎,首先要了解什么是搜索引擎。简单地理解,搜索引擎是一个系统,它可以帮助用户去互联网上搜集与其检索内容相关的信息。 通常,一个搜索引擎由搜索器、索引器、检索器以及用户接口组成,其中

京东 PC 首页 2019 改版前端操作总结

距离上次首页改版,已有2年3个月零五天。相比上次改版对首页整体框架、开发流程的大刀阔斧(前两次改版总结传送门:2016版,2017版),这次的改版看起来显得有点像跳水——没什么水花。在站在巨人肩膀上的

MySQL GRANT:用户授权

授权就是为某个用户赋予某些权限。例如,可以为新建的用户赋予查询所有数据库和表的权限。MySQL提供了GRANT语句来为用户设置权限。 在MySQL中,拥有GRANT权限的用户才可以执行GRANT语句

Redis链表(linked-list)数据结构和常用命令

链表结构是Redis中一个常用的结构,它可以存储多个字符串,而且它是有序的,能够存储2的32次方减1个节点(超过40亿个节点)。 Redis链表是双向的,因此即可以从左到右,也可以从右到左遍历它存储

Linux MiniShell实战视频教程(小江老师出品8集)

minishell实现的功能: 简单命令解析 管道行解析 输入输出重定向解析 一些内置命令实现 简单的信号处理 视频目录: [bbk5552]--Linux之MiniShell的实

MySQL子查询

前面我们介绍了如何使用SELECT、INSERT、UPDATE和DELETE语句对MySQL进行简单访问和操作。下面在此基础上开始学习子查询。 子查询是MySQL中比较常用的查询方法,通过子查询可以