C++ Primer 第八章 8.1 练习和总结

8.1 IO类

C++语言没有直接处理输入和输出,而是在标准库种定义了类型来处理IO

回忆我们之前学习的和IO有关的知识
1.istream 提供输入操作
2.ostream 提供输出操作
3.cin istream的对象,从标准输入(键盘)中读取数据
4.cout ostream的对象向标准输出(控制台)中输出数据
5. cerr ostream对象,向像准输出(控制台)输出数据
6. >> 其实是位运算符,重载之后的含义是从istream对象中读取数据
7. << 往ostream对象中输出值
8. getline(),从给定的istream对象中读取一行,存入string对象中。

之前学习到的和IO相关的知识,都是和标准输入和输出挂钩的,但是我们还可以从文件中读取和写入,也可以从string对象中读取和写入。

所以除了iostream类,C++标准库还定义了fstream和sstream。用来处理从文件中读取和写入,以及从存储在内存的string对象中读取和写入。

具体情况如下:
在这里插入图片描述
对于fstream和sstream的操纵方式和iostream的操纵方式是一样的,因为fstream和sstream继承自iostream。

所以类似于

int a;
cin>>a;
cout<<b;
string str;
getline(cin,str);

fstream和sstream的对象操纵的方式都是差不多。

8.1.1 IO对象没有拷贝和赋值

在之前的学习中,了解到iostream对象作为形参只能用引用或者指针的方式,

这是因为iostrem不准赋值和拷贝。

std::ifstream f_1;
	std::ifstream f_5;
	std::ifstream f_2 = f_1;//不能赋值
	std::ifstream f_3(f_1);//不能拷贝

同时之前还提到,因为操纵iostream对象时,对象内的状态会发生变化,所以iostrema对象的引用不能为常量。

这里所谓的状态变化,是IO类型的条件状态

扫描二维码关注公众号,回复: 9460898 查看本文章

他的状态包括。

1.badbit  //表示流已经崩溃
2.failbit //表示IO操作失败
3.eofbit  //表示遇到了文件结束符
4.goodbit //表示流正常

上面的4中状态是数据成员,可以直接使用iostream的对象直接访问。

cin.badbit

当我们使用io运算符时,io对象就会返回一个状态。这个状态可能是复合的类型的,通过位来表示。用来表示流的状态类型位iostate类型,

比如,当发生异常时,一个io对象可能有failbit和eofbit两个状态,。

我们直接使用单个状态需要使用位运算,比较麻烦,

所以,C++标准库还提供了判断iostrema对象状态的函数,以及获取和设置其状态的函数。

在这里插入图片描述

badbit表示系统级别的错误,一旦发生badbit,流就再也无法使用了。

但是如果是可恢复的错误,那么会触发failebit,比如

int a;
cin>>a;
输入了字符,这是可恢复的

当达到文件末尾时,出发eofbit和failbit。一个流对象的错误状态一旦发生,如果不恢复就会一直保持下去。

badbit,failebit,eof只要任意一个触发,检测流的状态条件就会失败。即:

if(cin){
	//块不会执行
}

我们可以通过clear(),setstate(),rdstate()来管理流

练习

8.1

stream& get_istream(istream& temp_input) {
	int a = 0;
	auto old_istream_state = temp_input.rdstate();
	while (true) {
		temp_input >> a;

		if (temp_input.eof()) {

			temp_input.setstate(old_istream_state);
			break;
		}
		else {
			//cout << a << endl;
		}
	}
	return temp_input;
}

8.3

1.输入了^Z即,文件结束符
2.输入不符合预期

int a;
cin>>a;

输入了字符

8.1.3 管理输出缓冲

IO操作是很耗时的,所以系统为了优化这种耗时,设立了缓冲区,缓冲区可以让多个输出操作变为单一的草错。

每一个输出流管理了一个缓冲区。
这里我不太理解,输出流指cin,cout,cerr这种输出流对象,还是ostream,ofstream,ostringstream这种类

我们使用cout输出信息,其实是把信息放入到缓冲区,然后再从缓冲区输出。

那么什么时候缓冲区会刷新呢。

1.程序正常结束
2.缓冲区满了
3。使用unitbuf来设置缓冲区状态,如果输出流是unitbuf状态,则缓冲区是立刻刷新的。cerr内部的状态就是unitbuf
4.使用操纵符endl显式刷新
5.将输出流关联到另一个留上,当读写被关联的流时,关联到的流的缓冲区会被刷新,默认情况下,cin和cerr都关联到cout。所以读cin和写cerr都会导致cout的缓冲区被刷新

除了使用endl可以显式的刷新流之外,还可以使用flush和ends

endl,输出一个换行符再刷新缓冲区,
flush,什么都不输出,刷新缓冲区
ends,输出一个空格符,刷新缓冲区

我们也可以使用unitbuf来设置流的状态是否需要立刻刷新。

cout<<unitbuf;// 所有的输出操作都会立刻刷新缓冲区
cout<<nounitbuf///恢复正常缓冲

用tie来关联对象,默认情况下
cin和cout都关联了cout;

cin.tie(&cout) //关联cout
cin.tie()//返回关联的对象指针

tie传入的是关联对象的地址,不是引用

发布了54 篇原创文章 · 获赞 6 · 访问量 3338

猜你喜欢

转载自blog.csdn.net/zengqi12138/article/details/104190530