C++ 为啥非常量数组声明不好? [复制]

Posted

技术标签:

【中文标题】C++ 为啥非常量数组声明不好? [复制]【英文标题】:C++ Why are non-const array declarations bad? [duplicate]C++ 为什么非常量数组声明不好? [复制] 【发布时间】:2019-07-19 04:41:06 【问题描述】:

如果我有以下两个陈述:

// OK
const int ARRAYSIZE = 5;
int x[ARRAYSIZE];

// NOT OK
int ARRAYSIZEBAD = 5;
int y[ARRAYSIZEBAD];

而且我没有使用 -pedantic-errors 标志进行编译...为什么第二个示例是一件坏事?在什么情况下最好对 new 运算符使用动态分配?

【问题讨论】:

这本身还不错,只是语言没有提供的功能。事物的大小必须在编译时知道,这意味着您需要在编译时知道数组大小的值。 " 在什么情况下最好使用 new 运算符的动态分配?"这可能是一个完全不同的问题。相关但与您的其他问题不同 除了NathanOliver所说的,如果你想像第二个例子那样动态创建一个数组,你可以使用int* y = new int[ARRAYSIZEBAD]; @user463035818 是的,这是对那个问题的欺骗...... @JoeBass“因为编译器这么说”不是很好的答案。更好的答案是“因为语言这么说”。 【参考方案1】:

C++ 为什么非常量数组声明不好?

因为数组的长度必须在编译的时候就知道了。如果一个变量是非常量的,那么它的值可能会在运行时改变,因此在编译时是未知的。只有编译时常量表达式可以用作数组的长度 - 因此 const 变量只能在观察到其初始化程序后用作数组的长度。

int[ARRAYSIZE] 是一种类型。在编译时知道大小的要求扩展到您实例化的所有类型,而不仅仅是数组类型。

在什么情况下最好使用动态分配...

编译时不知道数组长度时需要动态分配。

当数组很大时,您还需要非自动分配。这是因为为自动分配保留的内存通常非常有限。

... 使用 new 运算符?

使用 new 表达式分配动态内存很少见。 std::vector 通常在需要动态数组时使用。

【讨论】:

【参考方案2】:

它不好的原因是它不是有效的 C++ 代码。由于对可变长度数组 (VLA) 的支持,一些 C++ 编译器会对其进行编译,但这不是 C++ 语言的核心支持功能,并且不适用于所有符合标准的编译器。

在 C++ 中,如果您在编译时知道数组的长度,则应使用 std::array<int, 5>,它是“C 样式数组”的替代品和更好的版本,即 int arr[5];。如果您在编译时不知道长度,并且必须在运行时确定它,您应该使用std::vector<int>,它是int* arr = new int[5]; 的替代品,它具有您不需要的额外好处记得稍后再调用delete[],因为vector 对象将确保在对象出栈时正确调用删除器。

【讨论】:

"如果您在编译时知道数组的长度,则应该使用 std::array" -- 一条评论:仅当长度不太大时才适用大,因为太大的数组(在堆栈上)会导致堆栈溢出。【参考方案3】:

记住:C 和 C++ 不是 Java。例如,数组只是指向 N 块内存的指针。它们不是可以存储附加信息的对象,例如数组的大小。因此,编译器需要知道大小。

对于向量,原因并不明显。毕竟,您可以使用 int * 代替,然后分配您想要的任何大小。

但是如果你有一个多维数组,那么为什么编译器必须知道大小就变得更加明显了。

int myArray[3][3];

这仍然只是按 [0][0]、[0][1]、[0][2]、[1][0] 等顺序存储的 9 个 int 内存。所以要访问 myArray [2][1],编译器知道去第8个整数。

但这里有一些关于为什么它对一维数组很重要的更多信息。

int myArray[10];
int myNextArray[5];

在这种情况下,您有两段内存,一段长为 10 整数,另一段长为 5 整数。如果编译器不知道它们的大小,它如何知道它们各自占用了多少空间,所以它知道如何在你的方法开始时进行设置?

或者想象一下。

int size = 10;
int myArray[size];

size = 20;

数组有多大?

如果需要动态数组,请使用动态数组。

【讨论】:

" 例如,数组只是指向 N 块内存的指针" - 不,它们不是。数组不是指针。 "如果需要动态数组,请使用动态数组。" - 形式为std::vector. Neil Butterworth,当你传递一个整数数组时,你传递的是什么?你更喜欢我用什么词代替?处理?这对我来说听起来很OO。如果您能想出更好的表达方式,请随意,我可以编辑我的回复。 @JosephLarson 您可以传递数组(通过引用)、指向数组的指针或指向数组第一个元素的指针。 数组本身和它衰减到的指针之间的区别在这个特定问题的上下文中非常重要,这是关于数组本身而不是使用指向它们的指针。【参考方案4】:

正如一些人所指出的,C++ 通常在compile time 确定数组大小,而不是运行时。

变量的值在运行时设置,因此无法在编译时确定大小。也就是说,除了常量变量。常量变量在整个程序中都有一个常量值,因此可以在编译时确定。

如果您需要一个具有动态大小的数组,您可以选择 new 关键字:

int* y = new int[mySize];

当然,当你完成它时,你也应该删除它。

delete[] y;

编辑:感谢@WhozCraig 提醒我/指出您有比新建/删除更好的选择。您也可以使用vector

要使用,只需包含<vector>

#include <vector>

你可以这样使用它:

std::vector<int> y; // replace int with any type of object you want

这将允许您随时动态修改“数组”(可以这么说)的大小。

【讨论】:

delete [] y; 或者更好的还是把所有这些都扔给std::vector&lt;int&gt; y(mySize); 啊。好点。矢量要好得多。 另外,感谢您指出delete [] y; 的事情。我忘了哪一个是正确的。

以上是关于C++ 为啥非常量数组声明不好? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥这是 C++ 中的有效函数声明? [复制]

为啥在 C 中为数组声明和指向数组声明的指针动态分配的内存不同? [复制]

如果数组大小发生变化以及定义的宏如何在此处计算偏移量,为啥 C 结构中的字符数组的偏移量会有所不同? [复制]

为啥 Foo(b) 在 C++ 中编译成功? [复制]

在非常量对象上,为啥 C++ 不调用具有 public-const 和 private-nonconst 重载的方法的 const 版本?

为啥我可以在 C++ 中定义这个可变长度数组? [复制]