当大小是变量而不是常量时,如何创建数组?
我有一个接收变量int的方法。 该变量构成一个数组大小(请不要给我一个向量)。 因此,我需要在我的方法中初始化一个const int来初始化一个特定大小的数组。 问题:我该怎么做?
void foo(int variable_int){ int a[variable_int] = {0}; //error }
int *a = new int[variable_int];
完成后,请记得删除[]已分配的空间!
C ++不支持可变长度数组。 相反,您需要动态分配数组:
std::vector a(variable_int);
或者因为你说你出于某种原因不想使用矢量:
class not_a_vector { public: explicit not_a_vector(size_t size) : a(new int[size]()) {} ~not_a_vector() {delete [] a;} int & operator[](size_t i) {return a[i];} int operator[](size_t i) const {return a[i];} not_a_vector(not_a_vector const &) = delete; void operator=(not_a_vector const &) = delete; private: int * a; }; not_a_vector a(variable_int);
更新:问题刚刚用“C”标签和“C ++”更新。 C(自1999年以来)确实支持可变长度数组,因此您的代码应该适合该语言。
你问了一个非向量解决方案,但让我们来看看它,因为你可能因为错误的原因拒绝了它。 你不应该担心性能,因为在任何有能力的编译器的手中,它将具有与任何其他标准一致的解决方案几乎相同的开销。 另一方面,我将在下面介绍一些可读性和安全性问题。 让我们看一下从最推荐到最少的方式。
的std ::矢量
社区最喜欢的容器,有充分的理由。 它不仅可以使用运行时大小声明,而且可以随时更改大小。 当无法预先确定大小时,例如在重复轮询用户输入时,这便于使用。 例子:
// Known size size_t n; std::cin >> n; std::vector vec(n); // Unknown size std::vector vec; int input; while (std::cin >> input) { // Note: not always the best way to read input vec.push_back(in); }
使用std::vector
没有多少缺点。 已知大小的情况只需要一个动态分配。 在一般情况下,未知大小需要更多,但无论如何你都无法做得更好。 因此,性能或多或少是最佳的。
从语义上讲,对于在整个执行过程中保持不变的大小,它可能并不理想。 读者可能不明白这个容器不是要改变的。 编译器不知道它是否会让你做错了,比如把push_back
做成逻辑上常量大小的vector
。
std :: unique_ptr(或std :: shared_ptr)
如果强制执行静态大小,最安全的解决方案对您很重要。
size_t n; std::cin >> n; auto arr = std::make_unique(n);
arr
的大小不能改变,虽然它可以释放当前数组并指向另一个不同大小的数组。 因此,如果逻辑上容器的大小是恒定的,这将以更清晰的方式传达意图。 不幸的是,即使在恒定大小的情况下,它也比std::vector
弱得多。 它不是大小感知的,因此您必须明确存储大小。 出于同样的原因,它不提供迭代器,也不能在循环范围内使用。 如果您想牺牲这些function来强制执行静态大小,则由您(以及相关项目)决定。
最初我推荐了boost::scoped_array
但经过深思熟虑之后,我不相信它对这个解决方案提供了很多东西,所以我会坚持使用标准库。
new [] – 删除[]
从技术上讲,这是一个解决方案,但除非您被迫使用旧的C ++标准,或者您正在编写一个内部管理内存的低级库,否则它们严格地比std::unique_ptr
或std::shared_ptr
解决方案更糟糕。 它们不再提供更多function,但安全性显着降低,因为在完成内存后必须明确释放内存。 否则,您将泄漏它,这可能会导致严重的问题。 更糟糕的是,对于具有复杂执行流和exception处理的程序,正确使用delete[]
可能是非常重要的。 当您可以使用上述解决方案时,请不要使用此function!
size_t n; std::cin >> n; int* arr = new int[n]; ... // Control flow must reach exactly one corresponding delete[] !!! delete[] arr;
额外奖励:编译器扩展
有些编译器实际上可以使用以下代码
size_t n; std::cin >> n; int arr[n];
依靠这有严重的缺点。 您的代码无法在所有符合C ++标准的编译器上编译。 它可能甚至不能在给定编译器的所有版本上编译。 此外,我怀疑生成的可执行文件检查n
的值并在需要时在堆上分配意味着您可以炸毁堆栈。 只有当你知道n
的上限很小并且性能对你如此重要以至于你愿意依赖编译器特定的行为来获得它时,这个解决方案才有意义。 这些都是非常特殊的情况。
通过编写const int bar = variable_int;
可以很容易地从非const变量中创建一个const const int bar = variable_int;
– 但这对你没有帮助。 在C ++中,具有自动存储的数组的大小必须是编译时常量。 您无法将变量转换为编译时常量,因此您无法实现所需。
根据您的需要,您可以创建a
指针并使用new
分配内存(然后delete
其delete
),或者,如果foo
的参数在编译时始终是已知的,则可以将foo
转换为模板函数,如下所示:
template void foo() { int a[n] = {0}; }
要做你想做的事,你需要使用动态分配。 在这种情况下,我会认真建议使用向量 – 这是在C ++中做的“正确”的事情。
但如果你仍然不想使用矢量[为什么你不会超出我],正确的代码是:
void foo(int variable_int){ int *a = new int[variable_int](); // Parenthesis to initialize to zero. ... do stuff with a ... delete [] a; }
正如其他人所建议的那样,你也可以使用calloc,它具有与初始化为零相同的效果,但不是真正的“c ++”解决方案。
如果您正在使用数组,那么封装它们是个好主意:
template class Vector { //... };
标准库附带一个实现: std :: vector