我正在学习C ++。来自Java,很多东西对我来说都很奇怪。
在某些时候,我尝试创建一个在运行时确定的大小的数组,如下所示:
int size = functionCall(argument);
int array[size];
这已编译并运行,但在程序中稍后给出了非常奇怪的输出。
有人告诉我,我必须这样做:
int size = functionCall(argument);
int* array = new int[size];
因为new
允许动态分配东西,即如果我理解根据只在运行时知道的东西正确分配。
两个问题:
1-我对new
的理解是否正确?
2-为什么C ++不允许我的代码的第一个版本?
答案 0 :(得分:8)
在某些时候,我尝试创建一个在运行时确定的大小的数组,如下所示: 这编译并运行,但在程序中稍后给出了非常奇怪的输出。
您创建的是一个名为VLA的非标准扩展(A.K.A. Variable-length Array)。它本来应该有效,但是因为我没有假设你出错了。
因为new允许动态分配东西,即如果我理解根据只在运行时知道的东西正确分配。
是的,你的直觉是正确的。
1-我对新的理解是否正确?
是。您使用new
动态分配内存。但这又开启了另一种蠕虫病毒。
2-为什么C ++不允许我的代码的第一个版本?
C ++标准不支持VLA。我觉得这个问题的推理超出了问题的范围。
在任何一种情况下,如果你想要一个基于C ++中的运行时变量的动态数组,我们倾向于使用std::vector
。您的代码最终将成为这样:
std::size_t size = get_size();
std::vector<int> arr(size);
现在你可以使用std::vector
,好像它是一个普通的C数组。使用std::vector
而不是raw new的好处是,它可以减轻您使用delete[]
的负担,并且在您到达调用{{1}的行之前遇到异常时,它还提供强大的异常安全性}。
答案 1 :(得分:2)
C ++(与现代C不同)不允许使用在运行时计算的值初始化数组。可以做
int x[size];
在C ++中,但size
中包含的值必须由编译器知道。因此,以下是合法的
int const size = 10; // Known at compile-time
int x[size];
但以下不是
int size;
cin >> size; // we only know size at run-time
int x[size]; // ERROR!
这样做的原因是限制是技术性的,我不会在这里讨论,因为你对语言很新。只要知道如果你想声明一个数组(不使用关键字new
),你需要在编译时知道它的大小。
作为替代方案,您应该检查容器std::vector
,它允许您动态安全地分配数组,而不必使用new
和delete
。
std::vector<int> xs(10); // allocate space for ten ints.
好处是,由于vector的析构函数,您不必担心管理它分配的内存,从而导致更安全的代码。
所以,总结一下:
new
的理解是正确的。如果您只知道运行时的大小,则需要动态内存。但是,如果可能的话,请避免使用new
:首选vector
。答案 2 :(得分:1)
int size = functionCall(argument);
int* x = new int[size];
编译时不知道 size
。它只在运行时才知道。因此,您需要为数组使用heap allocation。编译器无法在编译时知道此数组的大小,因此它必须在运行时请求堆内存分配器在知道size
是什么时分配足够的空间。 new
关键字是对堆内存的请求。
如果你做了
static const int size = <constexpression>
int x[size];
例如,如果constexpression
是3
(size_t可转换文字)或编译时已知的任何内容,那么它将使用stack allocation,因为编译器会在编译时知道数组应该有多大,你可以这样做。
如果要创建一个连续的int数组,其大小只在运行时已知,则应使用std::vector
,它提供了一个可以在运行时动态调整大小的数组的安全包装: / p>
std::vector<int> x(size);
如果您在编译时知道大小,您甚至可以考虑使用std::array
,因为它具有静态size()
方法,不会占用任何额外的存储空间并且意味着您不需要传递大小同样(但是它会导致每个唯一size
编译时的实例化成本):
std::array<int, size> x; // where size is known at compile time