为什么在size_t的情况下抛出bad_alloc()异常

时间:2016-07-11 08:30:46

标签: c++ windows exception

我正在处理下面的代码,当我执行此代码时,我收到std::bad_alloc例外:

int _tmain(int argc, _TCHAR* argv[])
{
 FILE * pFile;

 size_t state;
 pFile = fopen("C:\\shared.tmp", "rb");
 if (pFile != NULL)
 {
    size_t rt = fread(&state, sizeof(int), 1, pFile);
    char *string = NULL;
    string= new char[state + 1];
    fclose(pFile);
 }
 return 0;
}

这下面的行导致抛出异常:

string = new char[state + 1];

为什么会发生这种情况,我该如何解决这个问题?

3 个答案:

答案 0 :(得分:7)

您正在传递未初始化的64位(现代64位系统上的8个字节)变量state的地址,并告诉fread读取sizeof(int) (相同系统上的32位,4个字节)从文件到此变量的字节。

这将覆盖读取值的变量的4个字节,但保留其他4个未初始化的字节。它覆盖的4个字节取决于体系结构(在Intel CPU上最不重要,在big-endian配置的ARM上最重要),但结果很可能是垃圾,因为4个字节未初始化并且可能包含任何内容

在您的情况下,很可能它们是最重要的字节,并且至少包含一个非零位,这意味着您尝试分配远远超过4GB的内存,这是您没有的。

解决方案是让state成为std::uint32_t(因为你显然希望文件包含4个字节代表无符号整数;不要忘记包含<cstdint>)和传递sizeof(std::uint32_t),并且通常确保对于传递指针和大小的每个fread和类似的调用,确保指针指向的东西实际上具有您传递的大小沿。传递size_t*sizeof(int)无法满足64位系统的这些要求,并且由于无法保证C ++的基本类型的大小,因此您通常不会想要将它们用于二进制I / O.

答案 1 :(得分:1)

你可以在C ++代码中改进各种各样的东西,但有很多原因,为什么你最终会遇到这种行为:

首先,变量state的类型为size_t,但您的代码会尝试使用fread(&state, sizeof(int), 1, pFile);初始化其值。现在,如果sizeof(state) != sizeof(int)那么你有未定义的行为。如果sizeof(state) < sizeof(int),那么fread语句通常会在存储变量state后覆盖一些任意内存。这会导致未定义的行为(例如state可能有一些随机大值,并且分配失败)。

其次,如果sizeof(state) > sizeof(int),则state仅部分初始化,其实际值取决于初始化(通过fread)和未初始化的位。因此它的值可能很大,分配可能会失败。

第三,如果sizeof(state) == sizeof(int)那么它可能只是读取的值太大,分配只是失败,因为你的内存不足。

第四,从文件中读取的值可能具有一些不同的编码或字节顺序。例如,如果value以big-endian格式写入文件,但在little-endian CPU上为fread,则可能导致字节被错误地交换。在使用read值之前,您可能需要交换字节。

我建议您使用<cstdint>(或<stdint.h>用于预C ++ 11)的某种固定宽度整数类型,例如变量std::uint64_t的{​​{1}} ,如果CPU的字节顺序与文件中存储的值的字节顺序不匹配,请使用state读取值,然后使用字节交换fread(&state, sizeof(state), 1, pFile);

答案 2 :(得分:0)

如果state大于此值,您应该决定您愿意分配的最大字符数是多少?几乎可以肯定,它是。