以下代码读取的文件包含一些值,该值表示更多后续数据的长度。
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
答案 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()
的零大小的空指针也会产生未定义的行为。标准。