C++IO类,输入输出缓冲区,流状态

我们的程序已经使用了很多IO库设施:

  • istream(输入流)类型,提供输入操作。
  • ostream(输出流)类型,提供输出操作。
  • cin,一个istream对象,从标准输入读取数据。写入到标准错误。
  • cout,一个ostream对象,向标准输出写入数据。
  • cerr,一个ostream对象,通常用于输出程序错误消息,
  • >>运算符,用来从一个istream对象读取输入数据。
  • <<运算符,用来向一个ostream对象写入输出数据。
  • getline函数(参见3.3.2节,第78页),从一个给定的istream读取一行数据,存入一个给定的string对象中。

 IO类

到目前为止,我们已经使用过的IO类型和对象都是操纵char数据的。

默认情况下,这些对象都是关联到用户的控制台窗口的。

当然,我们不能限制实际应用程序仅从控制台窗口进行IO操作,应用程序常常需要读写命名文件。而且,使用IO操作处理string中的字符会很方便。此外,应用程序还可能读写需要宽字符支持的语言。

为了支持这些不同种类的IO处理操作,在istream和ostream之外,标准库还定义了其他一些IO类型,我们之前都已经使用过了。

下表列出了这些类型,分别定义在三个独立的头文件中:

  • iostream定义了用于读写流的基本类型,
  • fstream定义了读写命名文件的类型,
  • sstream定义了读写内存string对象的类型。
IO库类型和头文件
头文件类型
iostreamistream, wistream从流读取数据
ostream, wostream向流写入数据
iostream, wiostream读写流
fstreamifstream,wifstream从文件读取数据
ofstream, wofstream向文件写入数据
fstream,wfstream读写文件
sstreamistringstream,wistringstream从string读取数据
ostringstream, wostringstream向string写入数据
stringstream, wstringstream读写string

 为了支持使用宽字符的语言,标准库定义了一组类型和对象来操纵 wchar_t类型的数据。宽字符版本的类型和函数的名字以一个w开始。

例如,wcin、 woout 和wcerr是分别对应cin、cout 和cerr的宽字符版对象。宽字符版本的类型和对象与其对应的普通char版本的类型定义在同一个头文件中。

例如,头文件fstream定义了ifstream和wifstream类型。

IO类型间的关系

概念上,设备类型和字符大小都不会影响我们要执行的操作。

例如,我们可以用>>读取数据,而不用管是从一个控制台窗口,一个磁盘文件,还是一个string读取。类似的,我们也不用管读取的字符能存入一个char对象内,还是需要一个wchar_t对象来存储。

标准库使我们能忽略这些不同类型的流之间的差异,这是通过继承机制实现的。

利用模板,我们可以使用具有继承关系的类,而不必了解继承机制如何工作的细节。

类型ifstream和istringstream都继承自istream。

因此,我们可以像使用istream对象一样来使用ifstream和istringstream对象。

也就是说,我们是如何使用cin的,就可以同样地使用这些类型的对象。

例如,可以对一个 ifstream或istringstream对象调用 getline,也可以使用>>从一个ifstream或istringstream对象中读取数据。

类似的,类型ofstream和ostringstream都继承自ostream因此,我们是如何使用cout的,就可以同样地使用这些类型的对象。

本节剩下部分所介绍的标准库流特性都可以无差别地应用于普通流、文件流和string流,以及char或宽字符流版本。

 IO对象无拷贝或赋值

我们不能拷贝或对IO对象赋值:

ofstream outl, out2;
outl = out2; // 错误:不能对流对象赋值
ofstream print (ofstream) ;// 错误:不能初始化ofstream参数
out2 = print (out2); //错误:不能拷贝流对象

由于不能拷贝IO对象,因此我们也不能将形参或返回类型设置为流类型。

进行IO操作的函数通常以引用方式传递和返回流。

读写一个IO对象会改变其状态,因此传递和返回的引用不能是const的。

条件状态 

IO 操作一个与生俱来的问题是可能发生错误。

一些错误是可恢复的,而其他错误则发生在系统深处,已经超出了应用程序可以修正的范围。

表中列出了IO类所定义的一些函数和标志,可以帮助我们访问和操纵流的条件状态。

IO库条件状态
strm::iostatestrm 是一种IO类型。iostate是一种机器相关的类型,提供了表达条件状态的完整功能
strm::badbitstrm::badbit用来指出流已崩溃
strm::failbitstrm::failbit 用来指出一个IO操作失败了
stm::eofbitstrm::eofbit用来指出流到达了文件结束
stm::goodbitstrm::goodbit用来指出流未处于错误状态。此值保证为零
s.eof()若流s的eofbit置位,则返回true
s.fail()若流s的failbit或badbit置位,则返回true
s.bad()若流s的badbit置位,则返回true
s.good()若流s处于有效状态,则返回true
s.clear()将流s中所有条件状态位复位,将流的状态设置为有效。返回void
s.clear(flags)根据给定的flags标志位,将流s中对应条件状态位复位。flaqs的类型为strm::iostate。返回void
s.setstate(flags)根据给定的flags标志位,将流s中对应条件状态位置位。flags的类型为strm::iostate。返回void
s.rdstate()返回流s的当前条件状态,返回值类型为strm::iostate


下面是一个IO错误的例子:

int ival;
cin >> ival;

如果我们在标准输入上键入Boo,读操作就会失败。

代码中的输入运算符期待读取一个int,但却得到了一个字符B。这样,cin会进入错误状态。类似的,如果我们输入一个文件结束标识,cin也会进入错误状态。

一个流一旦发生错误,其上后续的IO操作都会失败。只有当一个流处于无错状态时,我们才可以从它读取数据,向它写入数据。

由于流可能处于错误状态,因此代码通常应该在使用一个流之前检查它是否处于良好状态。

确定一个流对象的状态的最简单的方法是将它当作一个条件来使用:

while (cin >> word)
//ok:读操作成功…


while 循环检查>>表达式返回的流的状态。如果输入操作成功,流保持有效状态,则条件为真。

查询流的状态

将流作为条件使用,只能告诉我们流是否有效,而无法告诉我们具体发生了什么。

有时我们也需要知道流为什么失败。

例如,在键入文件结束标识后我们的应对措施,可能与遇到一个IO设备错误的处理方式是不同的。

IO库定义了一个与机器无关的iostate类型,它提供了表达流状态的完整功能。

这个类型应作为一个位集合来使用。

IO库定义了4个iostate类型的constexpr值,表示特定的位模式。

这些值用来表示特定类型的IO条件,可以与位运算符一起使用来一次性检测或设置多个标志位。

badbit表示系统级错误,如不可恢复的读写错误。通常情况下,一旦badbit被置位,流就无法再使用了

在发生可恢复错误后,failbit 被置位,如期望读取数值却读出一个字符等错误。这种问题通常是可以修正的,流还可以继续使用。

如果到达文件结束位置,eofbit和failbit都会被置位。goodbit的值为0,表示流未发生错误。

如果badbit、failbit和eofbit任一个被置位,则检测流状态的条件会失败。

标准库还定义了一组函数来查询这些标志位的状态。

操作good在所有错误位均未置位的情况下返回true,而bad、fail和eof则在对应错误位被置位时返回true。

此外,在badbit被置位时,fail也会返回true。这意味着,使用good或fail是确定流的总体状态的正确方法。实际上,我们将流当作条件使用的代码就等价于!fail()。而eof和bad操作只能表示特定的错误。

管理条件状态

流对象的rdstate成员返回一个iostate值,对应流的当前状态。

setstate 操作将给定条件位置位,表示发生了对应错误。

clear成员是一个重载的成员:它有一个不接受参数的版本,而另一个版本接受一个iostate类型的参数。

clear不接受参数的版本清除(复位)所有错误标志位。执行clear()后,调用good会返回true。

我们可以这样使用这些成员:

//记住cin的当前状态
auto old state = cin.rdstate();// 记住 cin的当前状态
cin.clear(); // 使cin有效
process_input (cin); //使用cin
cin.setstate(old state); // 将cin置为原有状态

带参数的clear版本接受一个iostate值,表示流的新状态。

为了复位单一的条件状态位,我们首先用rdstate读出当前条件状态,然后用位操作将所需位复位来生成新的状态。

例如,下面的代码将failbit和badbit复位,但保持eofbit不变:

//复位failbit和badbit,保持其他标志位不变
cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit);


 

管理输出缓冲

每个输出流都管理一个缓冲区,用来保存程序读写的数据。

例如,如果执行下面的代码

os << "please enter a value:";

文本串可能立即打印出来,但也有可能被操作系统保存在缓冲区中,随后再打印。

有了缓冲机制,操作系统就可以将程序的多个输出操作组合成单一的系统级写操作。

由于设备的写操作可能很耗时,允许操作系统将多个输出操作组合为单一的设备写操作可以带来很大的性能提升。

导致缓冲刷新(即,数据真正写到输出设备或文件)的原因有很多:

  • 程序正常结束,作为main函数的return操作的一部分,缓冲刷新被执行。
  • 缓冲区满时,需要刷新缓冲,而后续的数据才能继续写入缓冲区。
  • 我们可以使用操纵符,如endl来显式刷新缓冲区。
  • 在每个输出操作之后,我们可以用操纵符unitbuf设置流的内部状态,来清空缓冲区默认情况下,对cerr是设置unitbuf的,因此,写到cerr的内容都是立即刷新的
  • 一个输出流可能被关联到另一个流。在这种情况下,当读写被关联的流时,关联的流的缓冲区会被刷新。例如,默认情况下,cin和cerr都被关联到cout,读cin或写cexr都会导致cout的缓冲区被刷新。

刷新输出缓冲区 

我们已经使用过操纵符endl,它完成换行并刷新缓冲区的工作。

IO库中还有两个类似的操纵符:flush和ends。

  • flush刷新缓冲区,但不输出任何额外的字符;
  • ends向缓冲区插入一个空字符,然后刷新缓冲区:
cout << "hi!" << endl; //输出hi和一个换行,然后刷新缓冲区
cout << "hi!" <<flush;//输出hi,然后刷新缓冲区,不附加任何额外字符cout << "hi!" << ends;// 输出hi和一个空字符,然后刷新缓冲区

unitbuf 操纵符

如果想在每次输出操作后都刷新缓冲区,我们可以使用unitbuf操纵符。

它告诉流在接下来的每次写操作之后都进行一次flush操作。

而nounitbuf操纵符则重置流,使其恢复使用正常的系统管理的缓冲区刷新机制:

cout << unitbuf; // 所有输出操作后都会立即刷新缓冲区
// 任何输出都立即刷新,无缓冲
cout << nounitbuf; // 回到正常的缓冲方式

警告:如果程序崩溃,输出缓冲区不会被刷新

如果程序异常终止,输出缓冲区是不会被刷新的。当一个程序崩溃后,它所输出的数据很可能停留在输出缓冲区中等待打印。

当调试一个已经崩溃的程序时,需要确认那些你认为已经输出的数据确实已经刷新了。否则,可能将大量时间浪费在追踪代码为什么没有执行上,而实际上代码已经执行了,只是程序崩溃后缓冲区没有被刷新,输出数据被挂起没有打印而已。

关联输入和输出流

当一个输入流被关联到一个输出流时,任何试图从输入流读取数据的操作都会先刷新关联的输出流。

标准库将cout和cin关联在一起,

因此下面语句

cin >> ival;

导致cout的缓冲区被刷新。

交互式系统通常应该关联输入流和输出流。这意味着所有输出,包括用户提示信息,都会在读操作之前被打印出来。

tie有两个重载的版本;一个版本不带参数,返回指向输出流的指针。

如果本对象当前未关联到一个输出流,则返回的就是指向这个流的指针,如果对象未关联到流,则返回空指针。

tie的第二个版本接受一个指向ostream的指针,将自己关联到此ostream。即,x.tie(&o)将流x关联到输出流o。

我们既可以将一个istream对象关联到另一个ostream,也可以将一个ostream关联到另一ostream:

cin.tie(&cout); // 仅仅是用来展示:标准库将cin和cout关联在一起// old tie指向当前关联到cin的流(如果有的话)
ostream *old tie = cin.tie(nullptr); // cin不再与其他流关联//将cin与cerr关联;这不是一个好主意,因为cin应该关联到cout
cin.tie(&cerr); // 读取cin会刷新cerr而不是coutcin.tie(old tie); //重建cin和cout间的正常关联


在这段代码中,为了将一个给定的流关联到一个新的输出流,我们将新流的指针传递给了tie。

为了彻底解开流的关联,我们传递了一个空指针。每个流同时最多关联到一个流,但多个流可以同时关联到同一个ostream。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/796288.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows 下融合使用开源组件进行视频内容分析,shotcut ,autocut 剪辑 whisper智能化编辑双语字幕等

文章大纲 whisperautocut油管 视频分析视频数据下载下载字幕数据开源视频剪辑工具shotcut参考文献学习路径下面以这个黄仁勋访谈视频为例简要介绍分析的步骤 https://youtu.be/lXLBTBBil2Uwhisper https://github.com/openai/whisper提升: 安装如果需要在conda 中使用 ffmpeg …

电商技术揭秘七:搜索引擎中的SEO关键词策略与内容优化技术

文章目录 引言一、关键词策略1.1 关键词研究与选择1. 确定目标受众2. 使用关键词研究工具3. 分析搜索量和竞争程度4. 考虑长尾关键词5. 关键词的商业意图6. 创建关键词列表7. 持续监控和调整 1.2 关键词布局与密度1. 关键词自然分布2. 标题标签的使用3. 首次段落的重要性4. 关键…

C 语言中的 end, _end 符号

使用 man 3 end 可以看到相关符号的解释 这些符号不是在 C 语言文件和头文件中定义的&#xff0c;它们是 ld 在链接所有 .o 文件的时候自己添加的。 end 和 _end 的地址&#xff0c;就是最终程序的堆的起始地址 要打印它们的话&#xff0c;一个样例程序在下面&#xff1a; …

【opencv】示例-asift.cpp 对两张图片之间进行仿射特征比对

#include <opencv2/core.hpp> // 包含OpenCV核心功能的头文件 #include <opencv2/imgproc.hpp> // 包含OpenCV图像处理功能的头文件 #include <opencv2/features2d.hpp> // 包含OpenCV特征检测相关功能的头文件 #include <opencv2/highgui.hpp> // 包含…

关于阿里云云数据库自动扩缩容和自动SQL优化的20道面试题

1. 请解释阿里云云数据库自动扩缩容的概念及其工作原理。 阿里云云数据库自动扩缩容是一种基于数据库实例的实时性能数据&#xff0c;能够发现流量异常并提供合理的数据库规格建议和磁盘容量建议的功能。其工作原理如下&#xff1a; 性能监控&#xff1a;系统会实时监控数据库…

Java线程亲和实战

环境&#xff1a;Linux version 5.4.0-1084-aws (builddlcy02-amd64-044) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #91~18.04.1-Ubuntu SMP Sun Aug 14 01:24:43 UTC 2022 JDK: 1.8.0_241 CPU分配是如何工作的&#xff1f; 如果您有或提供了一个&#xff0c;该库…

sqlmap(五)

一、进行文件读写操作 1.1 前提条件 高权限 目录有读写权限 secure_file_priv " " 1.2 测试目标 第一步&#xff1a;用抓包的方式获取请求测试站点的数据包 可以使用Burpsuite 第二步&#xff1a;将抓到的数据包&#xff0c;保存到sqlmap目录下的a.txt 第三步&am…

FPGA和ARM学习那个比较好

FPGA和ARM是两种不同的技术&#xff0c;具有不同的应用领域和学习难度。以下是对两者进行比较的一些建议&#xff1a; 1. 应用领域&#xff1a;FPGA主要用于数字电路设计和硬件加速器开发&#xff0c;可在实时系统、信号处理、嵌入式系统等方面发挥重要作用。ARM则是一种处理器…

C++的vector类(二):vector类的实际OJ应用

1、只出现一次的数字 2、杨辉三角 3、删除有序数组中的重复项 4、只出现一次的数字 II 5、只出现一次的数字 III 6、数组中出现次数超过一半的数字 7、电话号码的字母组合 ~over~

从FasterTransformer源码解读开始了解大模型(1.1)一个decoder-only的模型长啥样

从FasterTransformer源码解读开始了解大模型&#xff08;1.1&#xff09;一个decoder-only的模型长啥样 写在前面的话 对于一个没有接触过LLM的初学者来说&#xff0c;如果想要了解一个大模型的推理框架&#xff0c;首先应该知道大模型整个的工作原理是怎样的&#xff0c;知道…

了解自动化机器学习 AutoML

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 自动化机器学习&#xff08;AutoML&#xff09;概述 自动化机器学习&#xff08;AutoML&#xff09;旨在自动化机器学习模型的开发流程&#xff0c;通过简化或去除需要专业知识的复杂步骤&#xff0c;…

CSS面试题常用知识总结day03

大家好我是没钱的君子下流坯&#xff0c;用自己的话解释自己的知识 前端行业下坡路&#xff0c;甚至可说前端已死&#xff0c;我还想在前段行业在干下去&#xff0c;所以从新开始储备自己的知识。 从CSS——>Javascript——>VUE2——>Vuex、VueRouter、webpack——>…

Stale Diffusion、Drag Your Noise、PhysReaction、CityGaussian

本文首发于公众号&#xff1a;机器感知 Stale Diffusion、Drag Your Noise、PhysReaction、CityGaussian Drag Your Noise: Interactive Point-based Editing via Diffusion Semantic Propagation Point-based interactive editing serves as an essential tool to compleme…

vite打包失败 - out of memory

在做项目时&#xff0c;随着需求的不断增加&#xff0c;我们的代码文件会越来越大&#xff0c;但是在打包时&#xff0c;在 Node 中通过 JavaScript 使用内存的大小却是有限制的。于是&#xff0c;今天打算部署代码时&#xff0c;报错了: <--- JS stacktrace ---> JS st…

Nuxt 3 项目中配置 Tailwind CSS

官方文档&#xff1a;https://www.tailwindcss.cn/docs/guides/nuxtjs#standard 安装 Tailwind CSS 及其相关依赖 执行如下命令&#xff0c;在 Nuxt 项目中安装 Tailwind CSS 及其相关依赖 npm install -D tailwindcss postcss autoprefixerpnpm install -D tailwindcss post…

VUE必知必会

一、简介 Vue.js是一个流行的JavaScript框架&#xff0c;用于构建用户界面和单页应用程序&#xff08;SPA&#xff09;。自2014年由前Google工程师尤雨溪发布以来&#xff0c;Vue迅速获得了广泛的关注和使用&#xff0c;特别是在前端开发领域。 核心特性 响应式数据绑定&#…

【cpp】快速排序优化

标题&#xff1a;【cpp】快速排序 水墨不写bug 正文开始&#xff1a; 快速排序的局限性&#xff1a; 虽然快速排序是一种高效的排序算法&#xff0c;但也存在一些局限性&#xff1a; 最坏情况下的时间复杂度&#xff1a;如果选择的基准元素不合适&#xff0c;或者数组中存在大…

vue基本写法

<p style"margin-left:.0001pt;text-align:justify;">Vue.js 是一种流行的 JavaScript 框架&#xff0c;用于构建用户界面。下面是 Vue.js 的一些标准写法和最佳实践:</p> 1. Vue 实例&#xff1a; 创建 Vue 实例时&#xff0c;可以指定一些选项来定义应…

Netty 3 - 组件和设计

这里将回顾我们之前章节讲到过的主要概念和组件。 1 Channel 、EventLoop和ChannelFuture Channel —— Socket;EventLoop —— 控制流、多线程处理、并发;ChannelFuture —— 异步通知。 1.1 Channel 接口 基本的I/O操作&#xff08;bind()、connect()、read()和write()&a…

【嵌入式开发 Linux 常用命令系列 4.3 -- git add 不 add untracked file】

请阅读【嵌入式开发学习必备专栏 】 文章目录 git add 不add untracked file git add 不add untracked file 如果你想要Git在执行git add .时不添加未跟踪的文件&#xff08;untracked files&#xff09;&#xff0c;你可以使用以下命令&#xff1a; git add -u这个命令只会加…