为什么 std::string::max_size "strange" 的值是 ?

Why is the value of std::string::max_size "strange"?

本文关键字:strange size std string max 为什么      更新时间:2023-10-16

我查看了std::string::max_size,注意到了以下示例:

#include <iostream>
#include <string>
int main ()
{
std::string str ("Test string");
std::cout << "max_size: " << str.max_size() << "n";
return 0;
}

输出:

max_size: 4294967291

然而,我一直认为这个限制是由于无符号整数/size_t的最大值,所以我有点希望它是2^32 - 1,也就是4294967295。为什么这个例子中的最大大小没有使用这4个字节?

我还试着运行示例代码,在那台机器上它是2^62——这再次让我感到困惑,为什么它不是2^64 - 1

总的来说,我想知道,一个实施会因为什么原因不使用所有的空间?

其中一个索引是为std::string::npos值保留的,它表示某些字符串函数中的"未找到"结果。此外,字符串在内部以null终止,因此必须为null终止字符保留一个位置。

这使我们达到了标准库可以提供的radix^bits - 3的理论最大值(除非这些保留位置可以共享相同的值;我不能100%确定这是不可能的)。据推测,该实现已经选择为内部使用再保留两个索引(或者我错过了一些必须保留的位置)。我可以想象,这种保留索引的一个潜在用途可能是溢出陷阱,它可以检测越界访问。

从实际角度来看:std::string::size_type通常与地址空间的宽度相同,在这种假设下,无论如何都不可能将整个地址空间用于单个字符串。因此,图书馆报告的数字通常是无法实现的;它只是标准库实现设置的上限,字符串的实际大小限制受到其他来源的限制,通常是可用RAM的数量。

除了eerorika写的…

  • 字符串可以(在多种情况下也可以)使用"奇怪"的布局。例如,在GCC 5的C++11一致字符串实现之前,std::string被实现为指向堆块(1)的单指针,该堆块包含字符数据和可能的NUL终止符,从指向的地址开始,但该字符数据的前面有大小、容量和引用计数(用于写时复制,也称为COW)
  • 一般来说,只有一种方法可以知道具体实现在做什么——查看其源代码
  • 需要实现来提供max_size(),并激励使max_size看起来足够大以用于实际目的。然而,它们往往提供不切实际的巨大价值。例如,从32位平面内存模型的实际角度来看,即使是2^32-5的数字也显得荒谬,因为它会假设程序的整个其余部分占用4个字节或更少(其中一个字节分配给字符串的NUL终止符)。AMD64上的2^62数字同样荒谬,因为即使是假设的完全实现的长模式(即需要未来的CPU)也"只"支持2^52个不同的物理地址(从技术上讲,交换或RAM压缩可以工作,但这真的是目的吗?)。顺便说一句,之所以选择2^62,而不是2^64减去一些小整数,是因为实现者至少意识到内核将始终保留部分虚拟地址空间用于其自身目的

长话短说……他们必须提供价值,所以他们这样做了,但他们不够关心,无法使其准确和有意义。至少您可以假设比max_size()长的字符串是绝对不可能的。

(1) :通常情况下,静态分配的空字符串是物理上很小但概念上很大的异常。