摘要
输入是世界进入程序的边界,而世界并不遵守规格说明。本课教人不加信任地读取:用 std::getline 读取整行,并避免它与 >> 混用时出现的空行;查询流的状态,并借此区分输入、输出与错误一课只见到混在一起的三种情形(无效数据、放不下的数和数据的结束);用 clear 和 ignore 从失败的读取中恢复;以及,作为最安全的做法,把每个数据当作文本读取,再用 std::from_chars 转换,只有当转换用尽了整段文本时才接受它。本课最后给出一个带契约的函数 readInt,课程的其余部分可以重复使用它。
学习目标
- 用
std::getline读取整行,解释为什么紧跟在>>读取之后的getline会返回空行,并用std::ws避免这种情况。 - 在读取之后用
fail()和eof()查询流的状态,并借此区分无效数据、放不进其类型的数和输入的结束。 - 编写一个读取循环,它用
clear和ignore从无效输入中恢复,并在输入结束时终止。 - 用
std::from_chars校验作为文本读入的数,要求没有错误并且用尽整个字符串,并把校验封装在带契约的函数中。
再谈边界
输入、输出与错误一课确立了关于 std::cin >> n 的三个事实:读取在第一个不能延续该数的字符处停下,并且不消耗它;如果一个字符也没能读到,流就进入错误状态,此后的每次读取都什么也不做;而 if (std::cin) 可以让人知道是否有什么失败了。循环一课又补充说,条件 while (std::cin >> value) 无论是输入结束还是遇到无效数据都会终止。然而,有了这些工具,程序能察觉出了问题,却不知道是什么问题,除了放弃也做不了别的。
本课从一条设计原则出发,即边界上的防御式编程:每个进入的数据在使用之前都要校验,而校验它的程序要把允许纠正的无效数据(再要一次、跳过、报告它)与不允许纠正的数据结束区分开来。既然如此,就需要三样东西:按数据写下的样子读取它,也就是读取一行;知道一次读取为什么失败;以及让流恢复读取的能力。
正在加载内容…
已完成
登录账户以保存您的进度