zoukankan      html  css  js  c++  java
  • C++ Primer- 流的条件状态以及缓冲区管理

    IO标准库提供了一系列条件状态成员,用来标记IO对象是否处于可用状态。使用strm::iostate类型的值来表示条件状态,

    这是一个跟机器有关的整型值,通过判断特定的一些位是否为1来判断流处于什么状态,有三个常量strm::badbit, strm::failbit, strm::eofbit 分别代表流被破坏,失败的IO操作和流已经到达文件尾。那么我们如何判断一个流比如说s处于什么状态呢,s.eof()若为true,表示到达文件尾,s.bad()若为ture,代表流被破坏,而 s.fail()若为true,则代表s遇到了失败的IO操作。

    我们现在可以通过这三个函数来判断流的状态,那么下一步,该如何改变这个流的状态呢,有以下几个函数:

    s.clear()          清除所有不可用的状态,重新使流有效

    s.clear(flag)      设置流的某一个不可用状态,如badbit状态,所以flag是strm::iostate类型的

    s.setstate(flag)   添加流的某一个不可用状态,如failbit状态,同样是strm::iostate类型值

    s.rdstate()        返回流的当前状态,是strm::iostate类型值

    这里我们通过一个例子来练习使用流的条件状态,题目是C++ Primer 练习8.3原题:

    编写一个函数,唯一形参和返回值都是istream&类型,该函数一直读取流直到到达文件结束符,同时把读到的内容输出到标准输出中,最后,重设流使其有效并返回,通过cin为实参实现调用来测试该函数。

    代码和注释如下:

    /**
    * @file    main.cpp
    * @brief   编写一个函数,可以一直读取流直到文件结束 并输出
    * @details
    * @author  jason.mrbourne@gmail.com
    * @date    2014-5-20
    */
    #include <iostream>
    #include <stdexcept>
    using namespace std;
    
    istream& get(istream& in)
    {
        int ival;
    
        //遇到文件结束符前一直读入数据
        while (in >> ival, !in.eof())
        {
            if (in.bad())   //出现系统级故障
                throw runtime_error("IO stream corrupted");
            if (in.fail())  //出现可恢复错误
            {
                cerr << "bad data, try again" << endl; //提示用户
                //有一些编译器不支持in.clear(istream::failbit)语句 所以这里用in.clear()
                in.clear();   //恢复流
                //跳过200个字符或者遇到空格或EOF为止 因此输入时必须以空格为间隔
                in.ignore(200, ' ');
                continue;   //继续读入数据
            }
            //读入正常
            cout << ival << '	';
        }
        in.clear();
        return in;
    }
    
    //在主函数中测试
    int main()
    {
        int ival;
    
        get(cin);       //这里用cin作为我们要读取的流
        cin >> ival;    //重新使用恢复后的流
        cout << ival << endl;
    
        return 0;
    }
    

    输出缓冲区的管理,输出缓冲区中存放着将要输出的数据,当程序结束或缓冲区满或执行一些清空缓冲区的操作时,系统会刷新缓冲区。

    c++提供3个操作符用于刷新流,用法如下:

    cout << “hi” << flush;      //刷新缓冲区,不添加数据

    cout << “hi” << ends;       //刷新缓冲区,并在输出中插入一个null空字符

    cout << “hi” << endl;       //刷新缓冲区,并在输出中插入一个换行符

    也可以用unitbuf操纵符来实现刷新,使用unitbuf会在每一次输出后刷新缓冲区。

    cout << unitbuf << “first” << “second”<< nounitbuf;

    这样在输出first后缓冲区被刷新,输出second后,缓冲区再次被刷新,此时缓冲区里啥也没有。但要最后用nounitbuff把流恢复正常。

    由于程序崩溃时,系统不会自动刷新缓冲区,那么此时想通过输出来找出错误发生的原因就变得异常艰难,基于这个原因,输出时应当尽可能使用endl而非’ ’。

    我们还可以将输入和输出绑在一起,默认标准库是将cout与cin绑在一起,这样在读cin的时候,会导致cout的缓冲区被刷新,我们可以使用tie()来制定需要绑定的流,例如:

    cin.tie(&cout);    //tie的参数为指向ostream对象的指针

    ostream* old_tie = cin.tie();    //返回当前与cin绑定的流指针

    cin.tie(0);        //解除cin的所有绑定,这样在读cin时,cout缓冲区将不会刷新

    cin.tie(&cerr);    //将cin与cerr绑定

    cin.tie(0);        //解除cin与cerr的绑定

    cin.tie(old_tie);  //恢复cin与cout的绑定   


  • 相关阅读:
    Java实现 LeetCode 802 找到最终的安全状态 (DFS)
    Java实现 LeetCode 802 找到最终的安全状态 (DFS)
    Java实现 LeetCode 802 找到最终的安全状态 (DFS)
    Java实现 LeetCode 804 唯一摩尔斯密码词 (暴力)
    Java实现 LeetCode 803 打砖块 (DFS)
    Java实现 LeetCode 804 唯一摩尔斯密码词 (暴力)
    Java实现 LeetCode 803 打砖块 (DFS)
    Java实现 LeetCode 804 唯一摩尔斯密码词 (暴力)
    英文标点
    post sharp 与log4net 结合使用,含执行源码 转拷
  • 原文地址:https://www.cnblogs.com/mrbourne/p/9959456.html
Copyright © 2011-2022 走看看