【问题标题】:Why is the value of std::string::max_size "strange"?为什么 std::string::max_size 的值“奇怪”?
【发布时间】:2019-02-05 14:19:52
【问题描述】:

我在看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

总的来说,我想知道,出于什么原因,实现不会使用所有空间?

【问题讨论】:

  • 依赖于实现,你试过不同的编译器和标准库吗?
  • 我猜想这与 (1) std::string 允许 NUL 字符和 (2) size() 必须是 O(1) 因此长度必须成为其有效负载的一部分,对于具有最大理论长度的字符串将占用 4 个字节。或者,它可能是用于短字符串优化的指针。
  • 然后铿锵回答18446744073709551599。所以问问不同的标准库实现者。你会得到更好的答案。
  • @Ayxan 实际上我不同意这个答案。限制不是由架构强加的,而是由库实现强加的。有时std::string::max_size() 会超出可用内存,而在某些架构上,您的可用内存很可能超过max_size 给出的限制。
  • @user463035818 好的,那你是对的。感谢您纠正我,但我不得不说像“The size of a string is only limited by the amount of memory available to the program, it is more of a operating system limitation than a C++ limitation”这样的陈述确实非常具有误导性。

标签: c++


【解决方案1】:

std::string::npos 值保留的最大可表示的索引之一,表示某些字符串函数中的“未找到”结果。此外,字符串在内部是空终止的,因此必须为空终止字符保留一个位置。

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

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

【讨论】:

  • 我认为他们实际上是在撒谎;在堆栈和堆位于同一地址空间的平台上,您需要sizeof(std::string) 来存储字符串本身。
【解决方案2】:

除了eerorika写的……

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

长话短说……他们必须提供一个价值,所以他们这样做了,但他们并没有足够在意以使其准确和有意义。至少你可以假设超过max_size() 的字符串绝对是不可能的。

(1):嗯,通常——静态分配的空字符串是物理上很小但在概念上很大的例外。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-02
    • 2012-10-19
    • 2016-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多