size_t和内存分配

Nik*_*ita 6 c++ memory-management c++11

有这样一种类型std::size_t.它可以用于描述对象的大小,因为它可以保证能够表达任何对象的最大大小(因此在这里写).但是,这是什么意思?我们实际上没有内存中的对象.那么这是否意味着这种类型可以存储一个整数,代表我们理论上可以使用的最大内存量?

如果我尝试写类似的东西

size_t maxSize = std::numeric_limits<std::size_t>::max();
new char[maxSize];
Run Code Online (Sandbox Code Playgroud)

我会得到一个错误,因为数组的总大小限制为0x7fffffff.为什么?而且,如果我传递一个等于的非常量表达式maxSize,std::bad_array_new_length将被抛出.如果我传递的表达式小于maxSize但仍然大于0x7fffffff,std::bad_alloc则会抛出.我想这std::bad_alloc是因为内存不足而引发的,不是因为大小大于0x7fffffff.为什么会这样?我想如果我们分配的内存大小大于0x7fffffff(这是在编译时传递给new []的const的最大值),抛出一个特殊异常是很自然的.为什么std::bad_array_new_length只有在我通过时才被抛出maxSize?这种情况特别吗?

顺便说一下,如果我将maxSize传递给vector的构造函数,如下所示:

vector<char> vec(maxSize);
Run Code Online (Sandbox Code Playgroud)

std::bad_alloc将被抛出,而不是std::bad_array_new_length.这是否意味着vector使用不同的分配器?

我正在尝试自己实现数组.使用unsigned int来存储大小,容量和索引是一种糟糕的方法.所以定义一些这样的别名是个好主意:

typedef std::size_t size_type;
Run Code Online (Sandbox Code Playgroud)

size_type而不是unsigned int

Oli*_*liv 3

答案是在创建动态存储持续时间的对象的过程中。

\n\n

简而言之,当程序执行新表达式new char[size]时::

\n\n
    \n
  1. 它检查s=size*sizeof(char)+x大小是否有效(实现定义为 0x7fffffff,这取决于 ABI)(如果您创建普通可破坏类型的数组,则在大多数平台上 x=0)。如果大小无效,则抛出bad_array_new_lenght,否则,

  2. \n
  3. 它调用分配函数::operator new(s)。这个函数的第一个参数是std::size_t,这就是为什么std::size_t必须足够大才能创建任意大小的对象(数组就是一个对象)。

  4. \n
  5. 该分配函数要求系统保留大小为 的存储区域s。如果系统成功保留该空间,它将返回一个指向存储区域开头的指针。否则它会调用一个新的处理程序并重试分配,但如果再次失败,则会抛出异常 bad_alloc

  6. \n
  7. 如果分配成功,它默认初始化(在这种情况下)size char分配的存储上的(无操作),并且它还可以在该分配的存储上存储数组的大小(添加的原因x)(这用于当执行删除表达式时,为了知道必须调用多少个析构函数。如果析构函数很简单,则没有必要)。

  8. \n
\n\n

您将在 C++ 标准中找到所有详细信息(\xc2\xa76.7.4 [basic.stc.dynamic]、\xc2\xa78.3 [expr.new]、\xc2\xa78.4 [expr.delete]、\ xc2\xa721.6 [support.dynamic])。

\n\n

对于最后一个问题,您可以考虑使用有符号类型作为索引和对象大小。即使对象大小或索引不应该为负,该标准也强制要求无符号算术遵循模算术,这严重限制了优化。此外,无符号整数类型算术和比较是错误的常见主题。std::size_t出于兼容性原因未签名,选择未签名是因为史前机器的位数很短!(16 位或更少!)

\n