当 getline() 读取的行大于系统内存时会发生啥?

Posted

技术标签:

【中文标题】当 getline() 读取的行大于系统内存时会发生啥?【英文标题】:What happens when getline() reads a line that is larger than system memory?当 getline() 读取的行大于系统内存时会发生什么? 【发布时间】:2020-10-28 00:52:39 【问题描述】:

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

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

【问题讨论】:

当库函数分配内存失败时一般会发生什么(例如std::vector.resize)?为什么你认为std::getline 会有所不同? 比你想象的更难捕捉。使用虚拟内存可以分配大量存储空间,比您计算机中可能拥有的存储空间多很多倍。从技术上讲,当程序要求的内存超出其所能获得的内存时,您会收到bad_alloc 异常,但操作系统可能在使用之前不会真正提供该存储。因此,系统很可能会允许分配,然后当承诺的存储无法满足时崩溃并烧毁,或者系统会因为一些较慢的存储被用作交换空间以提供更多空间而缓慢爬行。 【参考方案1】:

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

std::string 很可能早在发生之前就抛出类似std::bad_alloc 的内存错误。

【讨论】:

【参考方案2】:

来自cppreference(重点是我的):

从输入中提取字符并将它们附加到 str 直到其中之一 发生以下情况... c) str.max_size() 个字符已被 存储,在这种情况下 getline 设置失败位并返回。

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

所以,要处理错误,你可以catch(std::bad_alloc&)/*...*/

【讨论】:

【参考方案3】:

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

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

如果(不太可能?)您的系统确实拥有超过上述max_size() 可用内存字节,那么getline 调用将set the failbit flag 并在字符串到达​​时返回那个限制。


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

【讨论】:

以上是关于当 getline() 读取的行大于系统内存时会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

C++面向行输入:get()与getline()

可以在循环中多次使用 getline() 吗? - Cython,文件读取

如何从 C 中的控制台读取一行?

当填充大于定义的大小时会发生啥?

当内存位置的内容改变或被读取时自动中断

当 shuffle 分区大于 200 时会发生啥(数据帧中的 spark.sql.shuffle.partitions 200(默认情况下))