为什么operator new不能构造非常量大小的多维数组?

Why does operator new can't construct multidimensional array of non-constant size?

我可以为一维数组写operator new如下:

int n{3};
new int[n];

它至少分配 sizeof(int) * n 字节。但是当我想创建二维和多维数组时,只有第一维可能是非常量:

int n{3};
new int[n][3]; //ok
new int[n][n]; //error;

为什么会有这样的限制?确定至少要分配 sizeof(int) * n * n 字节有什么困难吗?

本例中的问题不在于确定要分配多少内存。这部分其实很简单,正如你自己注意到的那样。

问题是之后组织对这样一个数组的访问。如果您知道,C++ 中的多维数组是作为具有索引重新映射的线性(一维)数组实现的。例如,当您声明

int a[N][M];

编译器实际上在后台创建了一个 int [N * M] 数组。当您稍后以 a[i][j] 访问它时,后者只是隐含地转换为对 a[i * M + j] 的访问。 C++ 编译器坚持在编译时知道 M 的值(同时,请注意 N 的值根本不参与索引重新计算公式)。

这就是为什么在数组衰减为指针的情况下,多维数组的第一个大小无关紧要,而第二个、第三个和更多大小必须是编译时常量的原因。这也决定了对 new [] 施加的限制。

P.S。 C 语言支持可变长度数组,它允许所有大小都是 运行 时间值。这需要额外的努力,比如将 MN 的 运行 时间值与上述示例中的数组 a 一起存储。这最终被认为不适合 C++。

C++ 类型系统不包括运行时绑定的数组。这是一件非常复杂的事情,考虑到它会对模板和重载解析产生影响。已经有提案,但 none 已经进展到被标准化接受的程度。

因此 T[n] 不是有效类型。但是它可以用在 new-expression 中,因为它有一个特例。 new-表达式可以是:

  • new X,其中 X 是一个类型
  • new T[n],其中 T 是类型,n 不是常量表达式。

请注意,这两种情况都是必需的,因为 T[n] 不是类型,但我们希望在 new 表达式中允许它。

第二点需要多解释一下。它实际上使用 C++ 中缀表示法,因此如果 T 是数组或函数类型,[n] 将位于不同的位置。例如 new int[n][3] 是 OK ,与 typedef int T[3]; new T[n] 相同。但是 new int[3][n] 不是。

如果我们确实允许 new int[3][n],return 类型会是什么? int (*)[n] 不是前面提到的 C++ 类型系统的一部分。