为什么std::string::max_size()不等于std::string::allocator::max_size()

6

最近我注意到,以下语句不适用于std::string s

s.max_size() == s.get_allocator().max_size();

我觉得这很有趣,std::string默认使用的是std::allocator<char>,理论上的极限是size_type(-1)(是的,我知道我假设了2补码,但这与实际问题无关)。我知道实际限制要比这小得多。在典型的32位x86系统上,内核将占用2GB(也许是1GB)的地址空间,留下一个更小的实际上限。

无论如何,GNU libstdc++的std::basic_string<>::max_size()似乎会返回相同的值,而不管它正在使用的分配器是什么(大约是1073741820)。

因此,问题仍然存在,为什么std::basic_string<>::max_size()不只是返回get_allocator().max_size()呢?在我的看来,这是假设的上限。如果分配不足,它就会抛出一个std::bad_alloc,那为什么不试试呢?

这更多的是好奇心,我只是想知道为什么至少在这个实现中两者被单独定义。


如果分配不足,它就会抛出 std::bad_alloc 异常,那为什么不试试呢?我可以回答这个问题。人们可能需要处理大字符串,并将它们分成大字符串块,如果他们无法依赖于 max_size 向他们报告的内容,他们将不得不采取临时限制措施。 - GManNickG
我理解你的观点,但我不同意。事实上,你几乎总是必须假设任何字符串大小<= max_size() 都有可能失败,因为它取决于外部变量(堆中有多少可用空间)。 - Evan Teran
同意。我的唯一观点是他们至少应该尽量准确,而不是只给一个很大的数字然后期望最好的结果。给一个实际的数字,然后希望最好的结果。:) 虽然这个问题很棘手。 - GManNickG
3个回答

9
Microsoft Connect上发布了与您问题相关的错误。微软对此有一个有趣的答案:
我们根据标准的解释将其解决为“按设计”。标准没有清楚地解释max_size()的预期目的。分配器max_size()被描述为“可以有意义地传递给X::allocate()的最大值”(C++03 20.1.5 [lib.allocator.requirements]/Table 32),但容器max_size()被描述为“可能的最大容器大小”(23.1 [lib.container.requirements]/Table 65)。没有任何描述容器max_size()应该如何从分配器max_size()派生。多年来,我们的实现直接从分配器max_size()派生容器max_size(),然后使用这个值进行溢出检查等操作。其他对标准的解释,例如您的解释,是可能的,但对我们来说并不明确正确。这里标准的措辞肯定会受益于澄清。在这种情况下,除非发生这种情况,否则出于两个原因,我们决定保持当前的实现不变:(1)其他客户可能依赖于我们当前的行为,(2)max_size()本质上并没有什么用处。最多,消耗分配器(如容器)的东西可以使用分配器max_size()来预测allocate()何时会失败,但是简单地调用allocate()是更好的测试,因为分配器将决定是否提供内存。消耗容器的东西可以使用容器max_size()作为size()可能有多大的保证,但更简单的保证是size_type的范围。
此外,这里您可以找到Core Issue #197。委员会考虑了改善标准措辞的请求,但被拒绝了。
所以对于您的问题“为什么...?”的答案是,标准没有清楚地解释max_size()的预期目的。

4

据我所知,std::basic_string 目前的标准并没有限制字符串必须在连续的内存空间中存储。例如,它可以将字符串存储在多个块中。每个这样的块都受到 std::allocator::max_size() 的限制,但总和可能大于该值。

STL 容器似乎也是如此。毕竟,std::basic_string 是一个容器。


除非没有人以这种方式实现它,否则下一个标准可能不允许它(不完全确定),而且 OP 看到它比分配器允许的要显着 - UncleBens

1
GCC的实现有一条评论,说明他们如何计算max_size(必须减去内部管理对象的大小,该对象作为单个块与字符串一起分配),然后补充说max_size()返回这个值的四分之一。没有给出理由,也许只是一个安全裕量?(它也应该提供一个绳索类,也许你会用于如此大的字符串?)
使用VC++,max_size()返回allocator.max_size()减1的值——可能是为了考虑到结尾的空字符。

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