【问题标题】:What determines max_size in STL containers?什么决定了 STL 容器中的 max_size?
【发布时间】:2021-04-21 12:22:14
【问题描述】:

我试图在 C 中重现 std::string 的行为,但有一件事我真的不知道该怎么做。有一个max_size 成员方法可以提供字符串(或向量的任何其他数组等)可以具有的最大大小,所以我的问题是我知道这个值可能取决于系统,那么容器如何确定这个数字 ?我可以用 C 语言得到它吗?

【问题讨论】:

  • max_size 定义了该容器的特定实现理论上可以具有的最大大小。这个数字可能远远大于操作系统或硬件可以处理的数字。
  • 我认为它是由 allocator 提供的。
  • 根据您希望重新创建std::string 的忠实程度,您应该查看分配器,但也可以实现具有固定大小缓冲区的字符串类型,然后max_size() 将返回大小这个缓冲区。
  • 旁注:我认为通常std::basic_string<... char ...>::max_size(SIZE_MAX - 1) / 2,因此它适合“签名size_t”。

标签: c++


【解决方案1】:

什么决定了 STL 容器中的 max_size?

标准库的实现者选择它。考虑到 API 和目标系统施加的限制,实施者应该设计容器以支持尽可能大的大小。容器的实现失败,并且提供的分配器可能会施加额外的限制,理想情况下应该通过降低(因此更准确)max_size 来反映。

请注意,max_size 在实践中很少有用。这是一个理论上的上限,实际上不一定可以达到……通常是因为内存不足,至少在 64 位系统上是这样。它用于及早检测明显错误的用户输入(然后相应地抛出异常)。

我可以用 C 语言得到它吗?

您可以定义一个常量外部变量并在 c++ 翻译单元中对其进行初始化。示例:

// common_header.h
// add header guard here
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

extern const size_t cpp_string_max_size;
extern const size_t cpp_vector_int_max_size;

#ifdef __cplusplus
}
#endif

// source.cpp
#include "common_header.h"
#include <string>
#include <cstdlib>
#include <vector>

const std::size_t cpp_string_max_size = std::string{}.max_size();
const std::size_t cpp_vector_int_max_size = std::vector<int>{}.max_size();

然后,使用 C++ 编译器编译 C++ 翻译单元并将其与 C 程序链接。


我正在寻找一种不涉及任何 C++ 的方法

根据“任何 C++”的含义,您可以使用元编程:编写一个 C++ 程序,该程序生成一个 C 源文件,其中包含由 C++ 程序生成的常量。生成部分显然涉及到C++,但是生成的源码会是纯C,只用C编译器就可以编译。

如果这不符合您的喜好,您可以阅读您选择的 C++ 标准库的实现文件,看看它们是如何实现 max_size 的,然后手动编写 C 源代码。这不涉及任何时候编写或编译任何 C++,尽管它确实涉及读取 C++。

【讨论】:

  • 是的,我知道它没有用,但我还是想这样做,因为我想在我的 C 项目中尽可能忠实地重现 std::string 的行为,即使其中一些可能是善意的没用,感谢您的回复,但我正在寻找一种不涉及任何 C++ 并且只能使用gcc 的方法
【解决方案2】:

max_size 定义了该容器在理论上可以针对该容器的特定实现具有的最大大小。

该数字不取决于操作系统或可用内存,而仅由容器的实现给出。

如果你的(不兼容std::string)字符串容器的实现是这样的:

struct string {
   unsigned char size;
   char *data;

   // … further functions …
};

那么max_size 可能是指unsigned char 可以代表的最大数字。

如果您的实现只是一个\0 终止的字符串,没有任何其他元信息。那么max_size 可能是指对于给定的目标架构,可以通过指针寻址的最大字节数。

所以max_size 只是说,容器的实现方式将能够处理max_size 个元素。但这并不能保证操作系统能够做到这一点。


对于std::string,实现可以处理的最大字符数的上限size_type 的最大数量和一些进一步的限制给出。

std::stringsize_type 本身由使用的分配器 (std::allocator&lt;CharT&gt;) 给出,默认为 std::allocator_traits&lt;Allocator&gt;::size_type

对于std::allocatorsize_type 的推荐人std::size_t

所以对于std::stringmax_size上限std::size_t 的最大值减去满足字符串其他要求所需的值n

gcc-4.6.2libstdc++ 定义了says this 关于max_size

// The maximum number of individual char_type elements of an
// individual string is determined by _S_max_size. This is the
// value that will be returned by max_size().  (Whereas npos
// is the maximum number of bytes the allocator can allocate.)
// If one was to divvy up the theoretical largest size string,
// with a terminating character and m _CharT elements, it'd
// look like this:
// npos = sizeof(_Rep) + (m * sizeof(_CharT)) + sizeof(_CharT)
// Solving for m:
// m = ((npos - sizeof(_Rep))/sizeof(CharT)) - 1
// In addition, this implementation quarters this amount.
static const size_type  _S_max_size;
static const _CharT _S_terminal;

以及对应的initialization

template<typename _CharT, typename _Traits, typename _Alloc>
  const typename basic_string<_CharT, _Traits, _Alloc>::size_type
  basic_string<_CharT, _Traits, _Alloc>::
  _Rep::_S_max_size = (((npos - sizeof(_Rep_base))/sizeof(_CharT)) - 1) / 4;

根据这个197. max_size() underspecified(不确定是否有任何更新),max_size 的值不会因调用而改变:

LWG 很清楚,max_size() 返回的值不能随调用而改变。

因此您可以使用eerorika 的方法来获取特定分配器的值。

【讨论】:

  • 由于 std::string::npos 的要求,我认为它会小于这个值。
  • @Bathsheba 是的,可能是真的。更新了答案,显示的字符串类不是 std::string compatible 之一。
  • 但是std::string 的最大尺寸比我系统上的UCHAR_MAX 大得多。我打印了它,它是 18446744073709551599 而 ULLONG_MAX 是 18446744073709551615
  • @Fayeure 大小取决于 stdlib 的实现,因此可能会有所不同。我添加了有关libstdc++ 如何处理该问题的信息(链接指向较旧的来源)。如果您想要给定实现的实际值,则需要像其他答案中所示那样解决它。
猜你喜欢
  • 2012-12-02
  • 1970-01-01
  • 2010-11-23
  • 2012-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-03
相关资源
最近更新 更多