简体   繁体   English

当大小是变量而不是常量时,如何创建数组?

[英]How to create an array when the size is a variable not a constant?

I've got a method that receives a variable int. 我有一个接收变量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. 因此,我需要在方法内部初始化const int来初始化特定大小的数组。 Question: how do I do that? 问题:我该怎么做?

void foo(int variable_int){
    int a[variable_int] = {0}; //error
}
int *a = new int[variable_int];

完成后,请记住删除[]分配的空间!

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 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 . 使用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. 因此,性能或多或少是最佳的。

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. 尽管可以释放当前数组并指向另一个不同大小的数组,但是arr的大小不能更改。 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. 不幸的是,即使在恒定大小的情况下,它也比std::vector弱得多。 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. 是否要牺牲这些功能来实现静态大小取决于您(和相关项目)。

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. 从技术上讲是一种解决方案,但除非您被迫使用旧的C ++标准或正在编写内部管理内存的低级库,否则它们绝对比std::unique_ptrstd::shared_ptr解决方案差。 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. 更糟糕的是,对于执行和异常处理流程复杂的程序,正确使用delete[]可能并不简单。 Please don't use this when the above solutions are available to you! 当上述解决方案可供您使用时,请不要使用它!

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. 您的代码无法在所有符合C ++的编译器上进行编译。 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. 另外,我怀疑生成的可执行文件会检查n的值并在需要时在堆上分配,这意味着您可能会破坏堆栈。 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. 仅当您知道n的上限很小并且性能对您如此重要以至于您愿意依赖于编译器特定的行为来获取它时,此解决方案才有意义。 These are truly exceptional cases. 这些确实是例外情况。

C++ does not support variable-length arrays. C ++不支持可变长度数组。 Instead, you'll need to allocate the array dynamically: 相反,您需要动态分配数组:

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”标签和“ C ++”进行了更新。 C (since 1999) does support variable-length arrays, so your code should be fine in that language. C(自1999年以来)确实支持可变长度数组,因此您的代码在该语言中应该没问题。

You can easily make a const variable from a non-const variable by writing const int bar = variable_int; 您可以通过编写const int bar = variable_int;轻松地从非const变量中生成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-time constant. 在C ++中,具有自动存储功能的数组的大小必须是编译时常量。 You can't turn a variable into a compile-time constant, so what you want is simply not possible. 您不能将变量转换为编译时常量,因此根本无法实现所需的功能。

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的参数,则可以将foo变成这样的模板函数:

template<int n> void foo() {
    int a[n] = {0};
}

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++. 在这种情况下,我会认真建议改用向量-这是在C ++中要做的“正确”事情。

But if you still don't want to use vector [why you wouldn't is beyond me], the correct code is: 但是,如果您仍然不想使用vector [为什么您不会超出我的范围],则正确的代码是:

 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 ++”解决方案。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM