【问题标题】:Understanding the design of std::istream::read了解 std::istream::read 的设计
【发布时间】:2011-04-22 09:43:38
【问题描述】:

std::istream 有原型istream& read (char* s, streamsize n)实际读取的字节数应该通过调用istream::gcount() 来获得,istream 的有效性也可以从ios::good 中得知。

我正在与我的一位同事讨论我试图编写的另一个流类的实现,我说我可能会遵循这种设计;但他说,与其让用户每次都调用 gcount,不如阅读 istream& read (char* s, streamsize n, size_t &bytes_read) 这样的原型,这样它就可以在一次调用中结束,而前者更笨拙。我无法为std 的设计选择辩护。 istream::read 背后的真正原因是什么?

【问题讨论】:

  • 你的意思是size_t& bytes_written?而且,它可能应该是streamsize& bytes_written(或者可能是chars_read)。
  • @James:是的,谢谢! here 字节和字符是同义词,因为 sizeof 是相同的 :)

标签: c++ iostream istream c++-standard-library


【解决方案1】:

我认为这是因为 C++ 通常不会强制使用可能并非所有人都需要的接口。如果您要求read 接受一些人不关心的参数,那么它会导致额外的编码工作(声明一个额外的int 作为参数传递)。它还总是保存读取的字节,无论客户端是否关心(某些客户端可能只关心读取失败,如 eof/fail 位所示)。

使用单独的方法,您可以将可能需要或不需要的不同信息的接口解耦。

【讨论】:

    【解决方案2】:

    改用 readsome 命令,

    streamsize readsome ( char* buf, streamsize num );
    

    buf 是您的缓冲区,num 是您希望读取的字节数,当然最多是缓冲区中可用的字节数。

    返回值是实际读取的字节数。

    要读取文件到最后,您可以循环:

    char buf[BUF_SIZE]
    streamsize bytesRead;
    do
    {
       bytesRead = instr.readsome( buf, BUF_SIZE );
       // do stuff with the bytes you read, if any
    } while ( bytesRead == BUF_SIZE );
    

    【讨论】:

      【解决方案3】:

      std::istream有原型 istream& read (char* s, streamsize n) 实际读取的字节数 应该通过调用获得 istream::gcount(),也是有效期 的istream 可以从 ios::good.

      istream::read(char* s, streamsize n) 将大小为n 的未格式化数据块(没有NULL 终止)读取到位于s 的数组中。即使s 是指向char 的指针,您也可以使用istream::read 来读取二进制数据。例如,您可以有一个 istream 来保存双精度数组的值(假设字节顺序正确):

      unsigned int count;
      input.read(reinterpret_cast<char*>(&count), sizeof(count));
      double* data = new double[count];
      
      for (unsigned int i = 0; i < count; ++i)
          input.read(reinterpret_cast<char*>(data[i]), sizeof(double));
      

      istream::gcount() 返回上一次istream::read 调用中读取的字节数。在这种情况下,我们看到count 的大小可能与double 的大小不同,因此我们无法使用istream::gcount() 来指定data 数组中第一个元素的大小.

      【讨论】:

      • @CashCow 对istream::read的限制有正确的解决方案。我不能投票,因为我没有至少 15 分的声誉(我仍然是 Stack Overflow n00b)。
      • 我的实际问题是,为什么我们需要打电话给gcount;相反,为什么没有它,就像调用者可以传递一个引用变量一样,它将由read 设置为实际读取的字节数(可以小于或等于streamsize n),而不是调用者每次都调用 gcount .
      • 返回读取的字节数似乎更可取,如@CashCow 用istream::readsome 解释的那样。正如@Mark B 解释的那样,它避免了必须声明一个额外的 int 来通过引用传递。另一种选择是传递一个指向默认为NULL 的变量的指针,它可用于忽略读取的实际字节数:istream&amp; read(char* s, streamsize n, streamsize* bytesRead = NULL)。但是,我不知道它是否会比istream::readsome 提供显着优势。
      【解决方案4】:

      在回答最初的问题时,错误检查调用是 C 语言年轻时流行的一种编程风格,但很快就过时了。发生的事情是一些不是很错误的小事,但几乎总是存在一段时间,直到它们被社区称为坏事并被标记为坏事。不幸的是,这段代码是在这种小小的反模式被广泛讨论之前编写的。

      针对现金牛的解决方案,我认为有一个错误。如果您正在等待 IO 并且有足够的字符来部分填充缓冲区,那么函数将返回并且 while 循环将在文件被完全读取之前结束。因此,如果在直接原始 IO 之上编写,他的解决方案可能会正确运行,但在缓冲 IO 上运行会失败。

      当然,正确的解决方案是在设置 EOF 标志时结束 while 循环。目前我不确定设置 badbit 时的最佳响应是什么,但您可能也应该处理这种情况。

      不过,我同意 readsome 是一个不错的阅读替代品。

      编辑: 有时 readsome 不可用(某些 VC++ 版本)。在这种情况下,读取并非不可用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-07-13
        • 2013-10-30
        • 2011-02-04
        • 2019-07-12
        • 1970-01-01
        • 2012-03-19
        • 2011-02-22
        相关资源
        最近更新 更多