std :: iostream读取或写入计数为零且无效的缓冲区

时间:2015-06-29 16:15:36

标签: c++ c++11 iostream ostream istream

以下代码读取的文件包含一些值,该值表示更多后续数据的长度。

auto file = std::ifstream(filename, std::ios::in | std::ios::binary);
// dataLen = Read some header field containing a length of following data.
std::vector<unsigned char> data;
data.resize(dataLen);
file.read((char*)data.data(), dataLen);

如果dataLen = 0,则MSVC 2013编译器失败。它导致中止消息Expression: invalid null pointer,因为data.data()返回空指针。

This question 表示count 0对std::basic_istream::read有效,但对该问题的第三条评论似乎指出了我的问题。

将无效指针传递给大小为0的std::basic_istream::read(或std::basic_ostream::write)是否有效?这对我来说似乎是合乎逻辑的,因为无论如何呼叫都不应该触及缓冲区。

显而易见的解决方案是使用if子句来处理这个特殊情况,但我想知道MSVC是否再次出错。

以下是运行该程序的clang的编译示例:http://coliru.stacked-crooked.com/a/c036ec31abd80f22

1 个答案:

答案 0 :(得分:1)

以下是27.7.2.3 [istream.unformatted]第30和31段(重点是我的)中关于std::basic_istream<...>::read()的标准所说的内容:

basic_istream<charT,traits>& read(char_type* s, streamsize n);
     

效果:表现为无格式输入函数(如27.7.2.3第1段所述)。构造sentry对象后,如果!good()调用可能引发异常的setstate(failbit),则返回。否则提取字符并将它们存储到数组的连续位置,其第一个元素由 s指定。提取并存储字符,直到出现以下任何一种情况:

     
      存储
  • n个字符;
  •   
  • 文件结束在输入序列上发生(在这种情况下,函数调用setstate(failbit | eofbit),这可能会抛出ios_base::failure)。
  •   
     

返回*this

当一个函数被描述为将数组作为参数时,根据17.6.4.9 [res.on.arguments]第1段(被省略的文本适用于其他实体)可以传递的内容存在一些限制:

  

以下各项适用于C ++标准库中定义的函数的所有参数,除非另有明确说明。

     
      
  • 如果函数的参数具有无效值(例如函数域外的值或指针对其预期用途无效),则行为未定义。
  •   
  • 如果一个函数参数被描述为一个数组,那么实际传递给该函数的指针应该有一个值,使得所有地址计算和访问对象(如果指针指向第一个那么它将是有效的这种数组的元素)实际上是有效的。
  •   
  • ...
  •   

根据8.3.4 [dcl.array]第1段,实际数组不能为空(请注意,不存在常量表达式的情况会产生一个未指定大小的数组,最终仍会得到非零大小):

  

...如果存在constant-expression,它应该是std :: size_t类型的转换常量表达式,其值应更大   比零。 ...

由于空指针不能指向非空数组函数,因此期望传递数组会产生非空指针。换句话说,我认为您观察到的断言完全按顺序排列,根据标准给定义行为具有未定义行为的使用:即使传递给read()的零大小的空指针也会产生未定义的行为。标准。