C++ 当大小是变量而不是常量时如何创建数组?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14459248/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to create an array when the size is a variable not a constant?
提问by Denys S.
I've got a method that receives a variable int. That variable constitutes an array size (please, don't offer me a vector). Thus, I need to init a const int inside my method to initialize an array of specific size. Question: how do I do that?
我有一个接收变量 int 的方法。该变量构成数组大小(请不要提供向量)。因此,我需要在我的方法中初始化一个 const int 来初始化一个特定大小的数组。问题:我该怎么做?
void foo(int variable_int){
int a[variable_int] = {0}; //error
}
回答by patatahooligan
You asked for a non-vector solution but let's go over it because you might have rejected it for the wrong reasons. You shouldn't worry about performance because at the hands of any competent compiler it is going to have pretty much the same overhead as any other standard conformant solution. On the other hand, there are some readability and safety concerns that I'll go over below. Let's look at the ways you can do it from most recommended to least.
您要求使用非矢量解决方案,但让我们回顾一下,因为您可能出于错误的原因拒绝了它。您不应该担心性能,因为在任何有能力的编译器的手中,它的开销与任何其他符合标准的解决方案几乎相同。另一方面,我将在下面讨论一些可读性和安全性问题。让我们看看从最推荐到最不推荐的方法。
std::vector
标准::向量
The community's favorite container and for good reason. Not only can it be declared with a run-time size, but the size can be changed at any time. This facilitates use when size cannot be predetermined, eg when repeatedly polling for user input. Examples:
社区最喜欢的容器,这是有充分理由的。它不仅可以用运行时大小声明,而且可以随时更改大小。这有助于在无法预先确定大小时使用,例如在重复轮询用户输入时。例子:
// Known size
size_t n;
std::cin >> n;
std::vector<int> vec(n);
// Unknown size
std::vector<int> vec;
int input;
while (std::cin >> input) { // Note: not always the best way to read input
vec.push_back(in);
}
There's not much downside to using std::vector
. The known size case requires exactly one dynamic allocation. The unknown size requires more in the general case, but you wouldn't be able to do any better anyway. So performance is more or less optimal.
使用std::vector
. 已知大小的情况正好需要一个动态分配。在一般情况下,未知大小需要更多,但无论如何你都无法做得更好。所以性能或多或少是最佳的。
Semantically, it might not be ideal for sizes that are constant throughout the execution. It might not be apparent to the reader that this container is not intended to change. It is not known to the compiler either so it will allow you to do something wrong like push_back
into a vector
that is logically of constant size.
从语义上讲,对于在整个执行过程中保持不变的大小,它可能并不理想。读者可能不清楚此容器不打算更改。这是不知道的编译器要么所以它可以让你做了错事一样push_back
进入vector
了一个逻辑常量的大小。
std::unique_ptr (or std::shared_ptr)
std::unique_ptr(或 std::shared_ptr)
The safest solution if enforcing static size is important to you.
如果强制执行静态大小对您很重要,那么最安全的解决方案。
size_t n;
std::cin >> n;
auto arr = std::make_unique<int[]>(n);
arr
's size cannot change, though it can be made to release the current array and point to another one of different size. Therefore, if logically the size of your container is constant, this conveys intent in a clearer way. Unfortunately, it is also much weaker than std::vector
even in the constant-size case. It is not size-aware, so you have to explicitly store the size. For the same reason it does not offer iterators and can't be used in range for loops. It is up to you (and the project in question) if you want to sacrifice these features to enforce static size.
arr
的大小不能改变,但可以释放当前数组并指向另一个不同大小的数组。因此,如果逻辑上容器的大小是恒定的,这会以更清晰的方式传达意图。不幸的是,它也比std::vector
固定大小的情况弱得多。它不知道大小,因此您必须明确存储大小。出于同样的原因,它不提供迭代器,也不能在循环范围内使用。如果您想牺牲这些功能来强制执行静态大小,这取决于您(以及相关项目)。
Initially I had recommended boost::scoped_array
but after further thought I don't believe it has much to offer over this solution so I'll stick to the standard library.
最初我推荐过,boost::scoped_array
但经过进一步思考后,我不相信这个解决方案能提供太多东西,所以我会坚持使用标准库。
new[] - delete[]
新建[] - 删除[]
Technically a solution, but unless you are forced to use an old C++ standard or you are writing a low-level library that manages memory internally they are strictly worse than the std::unique_ptr
or std::shared_ptr
solution. They offer no more features, but are significantly less safe because you have to explicitly free the memory when you're done with it. Otherwise, you will leak it and this might cause significant problems. To make matters worse, using delete[]
properly can be non-trivial for programs with complicated flows of execution and exception handling. Please don't use this when the above solutions are available to you!
从技术上讲,这是一个解决方案,但除非您被迫使用旧的 C++ 标准,或者您正在编写一个在内部管理内存的低级库,否则它们比std::unique_ptr
orstd::shared_ptr
解决方案更糟糕。它们没有提供更多功能,但安全性明显降低,因为您必须在完成后明确释放内存。否则,您将泄漏它,这可能会导致重大问题。更糟糕的是,delete[]
对于具有复杂执行流程和异常处理流程的程序来说,正确使用可能并非易事。当上述解决方案可供您使用时,请不要使用它!
size_t n;
std::cin >> n;
int* arr = new int[n];
...
// Control flow must reach exactly one corresponding delete[] !!!
delete[] arr;
Bonus: Compiler extension
奖励:编译器扩展
Some compilers might actually be ok with the following code
一些编译器实际上可能可以使用以下代码
size_t n;
std::cin >> n;
int arr[n];
Relying on this has severe drawbacks. Your code cannot be compiled on all C++ conformant compilers. It probably doesn't even compile on all versions of the given compiler. Also, I doubt that the produced executable checks the value of n
and allocates on the heap when needed meaning you can blow up your stack. This solution only makes sense when you know the upper bound of n
is small and when performance is so important to you that you're willing to rely on compiler-specific behavior to get it. These are truly exceptional cases.
依赖于此具有严重的缺点。您的代码无法在所有符合 C++ 的编译器上编译。它甚至可能无法在给定编译器的所有版本上编译。另外,我怀疑生成的可执行文件会n
在需要时检查堆的值并在堆上分配,这意味着您可能会炸毁堆栈。只有当您知道 的上限n
很小并且性能对您如此重要以至于您愿意依靠特定于编译器的行为来获得它时,此解决方案才有意义。这些都是真正的例外情况。
回答by zennehoy
int *a = new int[variable_int];
Remember to delete[] the allocated space when you are done with it!
完成后记得删除[]分配的空间!
回答by Mike Seymour
C++ does not support variable-length arrays. Instead, you'll need to allocate the array dynamically:
C++ 不支持变长数组。相反,您需要动态分配数组:
std::vector<int> a(variable_int);
or since you say you don't want to use a vector for some reason:
或者因为您说出于某种原因不想使用向量:
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);
UPDATE: The question has just been updated with the "C" tag as well as "C++". C (since 1999) does support variable-length arrays, so your code should be fine in that language.
更新:问题刚刚更新为“C”标签以及“C++”。C(自 1999 年以来)确实支持可变长度数组,因此您的代码在该语言中应该没问题。
回答by sepp2k
You can easily make a const variable from a non-const variable by writing const int bar = variable_int;
- however that won't help you. In C++ the size of an array with automatic storage must be a compile-timeconstant. You can't turn a variable into a compile-time constant, so what you want is simply not possible.
您可以通过编写轻松地从非常量变量创建一个常量变量const int bar = variable_int;
- 但这对您无济于事。在 C++ 中,具有自动存储功能的数组的大小必须是编译时常量。你不能把一个变量变成一个编译时常量,所以你想要的根本不可能。
Depending on your needs, you could make a
a pointer and allocate memory using new
(and then later delete
it) or, if the parameter to foo
will always be known at compile-time, you could turn foo
into a template function like this:
根据您的需要,您可以创建a
一个指针并使用new
(然后使用delete
它)分配内存,或者,如果foo
在编译时始终知道参数 to ,您可以foo
变成这样的模板函数:
template<int n> void foo() {
int a[n] = {0};
}
回答by Mats Petersson
To do what you want, you will need to use dynamic allocation. In which case I would seriously suggest using vector instead - it is the "right" thing to do in C++.
为了做你想做的事,你需要使用动态分配。在这种情况下,我会认真建议改用 vector - 这是在 C++ 中做的“正确”的事情。
But if you still don't want to use vector [why you wouldn't is beyond me], the correct code is:
但是如果你仍然不想使用vector [why you won't is不如我],正确的代码是:
void foo(int variable_int){
int *a = new int[variable_int](); // Parenthesis to initialize to zero.
... do stuff with a ...
delete [] a;
}
As others have suggest, you can also use calloc, which has the same effect of initializing to zero, but not really the "c++" solution.
正如其他人所建议的那样,您也可以使用 calloc,它具有初始化为零的相同效果,但不是真正的“c++”解决方案。
回答by Peter Wood
If you're using arrays it's a good idea to encapsulate them:
如果您使用数组,最好将它们封装起来:
template<typename Type>
class Vector {
//...
};
The standard library comes with an implementation: std::vector
标准库带有一个实现:std::vector