【问题标题】:Why does operator new can't construct multidimensional array of non-constant size?为什么 operator new 不能构造非常量大小的多维数组?
【发布时间】:2017-03-29 01:46:29
【问题描述】:

我可以为一维数组编写 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 字节?

【问题讨论】:

  • 你不能有自动存储的VLA,为什么要允许它用于动态存储?
  • StoryTeller,但是对于一维数组它可以工作,为什么不允许它用于更多维数组?
  • 您没有 VLA,这意味着您无法拥有指向 VLA int (*)[n] 的指针,而这正是此类表达式需要返回的内容。
  • 最后,这一切都归结为 C++ 标准委员会没有发现 VLA 作为 C++ 的必要补充。我无法查看这些会议的记录,所以我无法告诉你原因。
  • @StoryTeller 允许 VLA 具有动态存储但不允许自动存储是一个可行的选择(对 VLA 的常见抱怨之一是它有堆栈溢出的风险)。

标签: c++ arrays multidimensional-array variable-length-array


【解决方案1】:

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

所以T[n] 不是有效类型。但是它可以在new-表达式中使用,因为它有一个特殊情况。 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],返回类型是什么? int (*)[n] 不是前面提到的 C++ 类型系统的一部分。

【讨论】:

    【解决方案2】:

    在这种情况下,问题不在于确定要分配多少内存。正如您自己指出的那样,这部分实际上很简单。

    问题在于事后组织对此类数组的访问。如果您知道,C++ 中的多维数组被实现为具有索引重映射的线性(一维)数组。例如,当你声明

    int a[N][M];
    

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

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

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

    【讨论】:

      猜你喜欢
      • 2018-10-08
      • 2020-10-22
      • 2016-03-15
      • 2017-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多