共计 936 个字符,预计需要花费 3 分钟才能阅读完成。
前几天在回答问答栏目的问题时,犯了一个错误,本文章是关于错误原因的分析。
我将问题中的程序简化为以下代码:
#include <iostream>
int main() {
std::string input;
while (std::cin >> input) {
std::cout << input << std::endl;
}
}
当时我认为 while 循环会一致循环下去,因为 >> 操作符的重载是这样的:
总是返回 basic_istream 的引用,因为不为空,所以转换成 true。可转念一想,以前我也这么写过,而且很多人也这么写,应该理解有误,故重新审视这个问题。
std::cin >> input 控制着循环的执行,下面按表达式执行顺序分两步说明:
第一步:提取操作符重载
如上图所示,>> 操作符将字符串读入 input 之后,会返回 basic_istream 的引用。这个引用是非空的,如果仅仅到这一步,肯定会返回 true 的。然而,C++ 的标准库做了一个特殊处理,进入下一步。
第二步:转换操作符重载
cin 在 <iostream> 声明如下:extern std::istream cin; 且,istream 是 basic_istream<char> 的别名,所以 cin 实际上也继承了基类 basic_istream<> 的成员和成员函数。
而,basic_istream 有关于转换操作符的重载:
如果输入流没有错误,第一个函数 (C++11 之前的版本) 会返回非 NULL 指针(在 while 里又再次转换为 true),第二个函数会返回 true。
当然我们可以用以下的测试程序验证我们的结论,我们手工用 setstate 函数设置了输入流的状态:
#include <iostream>
int main() {
std::string input;
while (std::cin >> input) {
std::cout << input << std::endl;
std::cin.setstate(std::ios_base::failbit);
}
}
这个时候,循环结束。所以,while 中 std::cin >> input 的返回是跟流的状态相关的。
综上,之所以犯错,主要是因为第二步的转换操作符“作祟”,C++ 的隐式转换在某种程度上会带来理解的成本,使用时要加倍小心。
关注我的公众号哈