43

为什么可以 while(std::cin >> input)(C++)

 4 years ago
source link: https://mp.weixin.qq.com/s?__biz=MzU4OTQyODI0Mw%3D%3D&%3Bmid=2247483781&%3Bidx=1&%3Bsn=52e95c7fa400e5dc9f918ceca1987b52&%3Bchksm=fdcce2f9cabb6bef49daec6df5c3df7c0d89329581e82b2506ff015951785aac5dbd09456c2d
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

(点击 上方公众号 ,可快速关注)

前几天在回答问答栏目的问题时,犯了一个错误,本文章是关于错误原因的分析。

我将问题中的程序简化为以下代码:

#include <iostream>int main() {
    std::string input;    while (std::cin >> input) {
        std::cout << input << std::endl;
    }
}

当时我认为 while 循环会一致循环下去,因为 >> 操作符的重载是这样的:

zuMbemn.jpg!web

总是返回 basic_istream 的引用,因为不为空,所以转换成 true 。可转念一想,以前我也这么写过,而且很多人也这么写,应该理解有误,故重新审视这个问题。

std::cin >> input 控制着循环的执行,下面按表达式执行顺序分两步说明:

第一步:提取操作符重载

如上图所示, >> 操作符将字符串读入 input 之后,会返回 basic_istream 的引用。这个引用是非空的,如果仅仅到这一步,肯定会返回 true 的。然而, C++ 的标准库做了一个特殊处理,进入下一步。

第二步:转换操作符重载

cin<iostream> 声明如下:

extern std::istream cin;

且, istreambasic_istream<char> 的别名,所以 cin 实际上也继承了基类 basic_istream<> 的成员和成员函数。

而, basic_istream 有关于转换操作符的重载:

67VjQj3.png!web

如果输入流没有错误,第一个函数(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);
    }
}

这个时候,循环结束。所以, whilestd::cin >> input 的返回是跟流的状态相关的。

综上,之所以犯错,主要是因为第二步的转换操作符“作祟”,C++的隐式转换在某种程度上会带来理解的成本,使用时要加倍小心。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK