为什么 std::string::max_size 的值看起来很奇怪?

9

我在查看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呢?
总的来说,我想知道,出于什么原因实现不会使用所有空间?

2
实现依赖性很大,你尝试过使用不同的编译器和标准库吗? - Matthieu Brucher
2
我猜测这可能与以下事实有关:(1)std::string 允许 NUL 字符,(2) size() 必须为 O(1),因此长度必须是它的有效负载的一部分,这将占用 4 个字节,对于最大理论长度的字符串。或者,这可能是用于短字符串优化的指针。 - Bathsheba
2
而clang的答案是18446744073709551599。因此请咨询不同的标准库实现者,你会得到更好的答案。 - Matthieu Brucher
2
@Ayxan,实际上我不同意那个答案。限制并不是由架构所强加的,而是由库的实现所决定的。有时候std::string::max_size()超过了可用内存,而在某些架构上,你可能拥有比max_size给出的限制更多的内存。 - 463035818_is_not_a_number
2
@user463035818 好的,那么你是正确的。感谢你纠正我,但我必须说像“字符串的大小仅受程序可用内存的限制,这更多是操作系统的限制而不是C++的限制”这样的陈述确实非常误导人。 - Ayxan Haqverdili
显示剩余6条评论
2个回答

7
其中一个索引,具体来说是最大可表示的索引,被保留给std::string::npos值,在某些字符串函数中表示“未找到”结果。此外,字符串在内部以空字符结尾,因此必须为空字符保留一个位置。
这将使我们达到理论上的最大值radix^bits - 3,标准库可以提供如此之多(除非那些保留的位置可以共享相同的值;我不确定这是否不可能)。假定实现已经选择为内部使用保留两个以上的索引(或者我错过了一些必要的保留位置)。我可以想象这种保留索引的潜在用途可能是溢出陷阱,它检测超出边界的访问。
从实际角度考虑: std::string::size_type通常与地址空间的宽度相同,根据这样的假设,无法实际使用整个地址空间来存储单个字符串。因此,标准库报告的数字通常是不可达到的,只是由标准库实现设置的上限,并且字符串的实际大小限制取决于其他来源的限制-通常是可用RAM的数量。

我认为实际上他们在说谎;在堆栈和堆都在同一地址空间的平台上,你需要使用sizeof(std::string)来存储字符串本身。 - Yakk - Adam Nevraumont

2
除了eerorika写的内容之外...
  • 字符串可以(而且在多种情况下确实)使用“奇怪”的布局。例如,在GCC 5的C++11兼容的字符串实现之前,std::string被实现为指向包含字符数据和可能的NUL终止符的堆块(1)的单个指针,该字符数据以指向的地址开头,但该字符数据前面还有大小、容量和引用计数(用于写时复制即COW)。
  • 通常,了解特定实现正在做什么的唯一方法是查看其源代码。
  • 实现必须提供max_size(),并有动力使max_size看起来足够大以实际使用。然而,它们经常提供不现实istically大的值。例如,即使在32位平面内存模型上,2^32-5的数字似乎从实际角度来看也很荒谬,因为它会假设整个程序的其余部分占用4个字节或更少(其中一个字节用于字符串的NUL终止符)。AMD64上的2^62数字同样荒谬,因为即使是一个假设的完全实现的长模式 - 即需要未来的CPU - 也将“仅”支持2^52个不同的物理地址(从技术上讲,交换或RAM压缩可以工作,但这真的是意图吗?)。顺便说一句,选择2^62而不是,比如说,2^64减去一些小整数的原因是,实现者至少意识到内核总是会为自己的目的保留一部分虚拟地址空间。
长话短说...他们必须提供一个值,所以他们提供了,但他们不在乎使它准确和有意义。至少你可以假设比max_size()更长的字符串绝对不可能。
(1): 好吧,通常来说,静态分配的空字符串是物理上微小但概念上很大的例外情况。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接