当getline()读取一个大于系统内存的行时会发生什么



假设C++getline()从某个文件中读取,该文件中有一条巨大的行超过了系统的内存容量(在超过内存容量之前没有换行符(。那么while(getline(cin, line))循环的作用是什么?

而且,如果我需要通过抛出异常或其他什么来处理这种可能的边缘情况,我该怎么做?

如果std::getline()最多读取std::string::max_size()个字符,它只需停止读取并在输入流上设置failbit标志。

不过,std::string可能会在发生之前很久就抛出类似std::bad_alloc的内存错误。

来自cppreference(重点是我的(:

从输入中提取字符,将它们附加到str,直到出现以下情况。。。c( str.max_size((个字符存储,在这种情况下,getline设置failbit并返回。

理论上,符合标准的实现可以使max_size()返回比可用虚拟内存更低的值,在这种情况下,读取将停止。通常情况下,情况并非如此,内存将首先耗尽。追加下一个字符将触发失败的分配处理机制,默认情况下,该机制将抛出std::bad_alloc

因此,为了处理错误,您可以只使用catch(std::bad_alloc&){/*...*/}

假设系统的内存容量小于std::string::max_size()的值(这可能相当于64位系统上超过800万TB(,那么getline()函数在某个阶段,当STL实现尝试(但失败(为作为getline()调用的第二个参数传递的std::string对象分配额外空间时,抛出std::bad_alloc异常。

因此,您只需要将getline调用包含在try块中,并将catch包含在该异常中。

如果(不太可能?(系统的可用内存超过上述max_size()字节,则getline调用将设置failbit标志,并在字符串达到该限制时返回。


1例如,在我的64位Windows系统上使用Visual Studio 19时,max_len()返回9223372036854775807,即8388607 TB。

在我的Ubuntu 22.04上,它设置badbit而不抛出std::bad_alloc,除非我将其设置为在badbit上抛出。我怀疑它是在标准中写的,但我不确定。

以下程序:

#include <iostream>
#include <string>
int main() {
std::string s;
std::getline(std::cin, s);
std::cout << "okn";
std::cout << std::cin.eof() << std::cin.bad() << std::cin.fail() << "n";
}

当使用g++ a.cpp -o a编译并使用tr '' ' ' </dev/zero | ( ulimit -v 500000; ./a )运行时(获得无限的空间流,内存限制为~500MB(会打印以下内容:

ok
011

这里还设置了CCD_ 29;可能是因为管子坏了什么的。

使用libc++的Clang表现出相同的行为。

此外,您可以清楚地看到,这正是标准库源代码中描述的行为:捕获异常,设置badbit,忽略异常,除非流设置为在badbit上抛出。请参见libstdc++、libc++。

最新更新