没有常量表达式的C ++数组大小

时间:2016-03-23 12:43:12

标签: c++ arrays

我正在阅读Stroustrup's C ++之旅。在第9页,他说:

  

"数组的大小必须是常量表达式。"

然而,后来,pg。 16,他使用以下代码示例:

void vector vector_init(Vector& v, int s)
{
  v.elem = new double[s]; // Allocate an array of s doubles
  v.sz = s;
}

此处s不是常量表达式,因此如何将v.elem初始化为new double[s]合法?

3 个答案:

答案 0 :(得分:39)

分配的数组(即使用new[]表达式创建的数组(如new double[s])之间存在差异,其生命周期必须由代码管理(via {{ 1}})和声明数组,其生命周期仅由其范围管理:

delete[]

区别不是基于堆栈/堆。声明的数组可以堆栈分配(例如int* p = new int[s]; // allocated array, p has type int* int q[10]; // declared array, q has type int[10] std::vector<int> u; // has member allocated array std::array<int, 5> v; // has member declared array )或不在堆栈上(例如new array<int,5>

使用分配的数组,大小不必是常量表达式。大小将被简单地编码到分配器以某种方式产生的存储器块中(例如,在实际数据开始之前的四个前导字节),以便相应的static double x[100];知道要删除多少元素。

使用声明的数组(或未分配的数组,没有delete[] / new / etc。),大小必须为编码到类型中,以便析构函数知道该怎么做。唯一允许的标准数组声明是:

malloc

(其中T D[constant-expression_opt]; 是一个可以是名称或其他数组声明的声明符,等等。)声明的数组不限于堆栈。请注意,为了增加混淆,constant-expression是可选的。

数组在C ++中提供了许多混淆源。分配和声明的数组具有不同的大小规则和不同的管理实践,但您可以为其中任何一个分配D,并且它们等效地编入索引。分配的数组一个指针(你得到的全部),但声明的数组衰减指针(但一个阵!)。

请注意,可变长度数组(VLA)的概念。例如,gcc支持它们作为扩展,但它们是非标准的C ++。它会定期提出,您可以看到this question以获取有关它们的更多信息。

答案 1 :(得分:11)

创建内存由编译器管理的数组时,其大小必须为(编译时)常量。例如:

int a[5];
const int sz = 7;
int b[sz] = {0};

(例如,某些语言:C(C99以后)支持动态数组大小)

如果你想要一个动态大小的数组(由你给出的示例片段),你需要自己为它分配内存,你还需要在完成后用delete释放它。这种数组的大小也可以是非const的。此外,您需要自己管理内存,分配可能会失败,运算符(例如sizeof)将对指针而不是数组进行操作。

在现代C ++(C ++ 11及更高版本)中,即使是stl容器std::array也必须具有恒定的大小。

答案 2 :(得分:4)

报价

  

数组的大小必须是常量表达式。

正在讨论数组声明,例如

double a[EXPR];

其中EXPR必须确实是常量或constexpr(C具有可变长度数组,但它们不是标准C ++的一部分)。

你提到的表达式作为反例,

new double[s]

不是数组,尽管[]。它是new-expression,产生指针,而不是数组。你没有显示v.elem的定义,但我可以告诉它是指向双倍的指针。

关于新表达式

的链接讨论
  

如果type是数组类型,则必须将除第一个之外的所有维度指定为正{类似于整数常量 - 详细信息}。

所以上面提到的类型double[s],这是明确允许的。

不可否认,数组和传递给新表达式数组类型之间的区别有点微妙,但你不能因为[]而将它们混为一谈比你声称的那样

map["key"]

通过声明长度为"key"的数组来违反某些内容。