4

我有一个接收变量 int 的方法。该变量构成一个数组大小(请不要给我一个向量)。因此,我需要在我的方法中初始化一个 const int 来初始化一个特定大小的数组。问题:我该怎么做?

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

6 回答 6

13

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.

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.

std::unique_ptr (or 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.

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.

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!

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.

于 2017-10-03T22:00:06.883 回答
9
int *a = new int[variable_int];

完成后记得删除[]分配的空间!

于 2013-01-22T13:05:55.490 回答
4

C++ 不支持变长数组。相反,您需要动态分配数组:

std::vector<int> 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 年以来)确实支持可变长度数组,因此您的代码在该语言中应该没问题。

于 2013-01-22T13:14:19.903 回答
3

您可以通过编写轻松地从非常量变量创建一个 const 变量const int bar = variable_int;——但这对您没有帮助。在 C++ 中,具有自动存储功能的数组的大小必须是编译时常量。您无法将变量转换为编译时常量,因此您想要的根本不可能。

根据您的需要,您可以创建一个指针并使用(然后再使用它)a分配内存,或者,如果参数 to在编译时总是已知的,您可以变成这样的模板函数:newdeletefoofoo

template<int n> void foo() {
    int a[n] = {0};
}
于 2013-01-22T13:11:13.500 回答
2

为了做你想做的事,你需要使用动态分配。在这种情况下,我会认真建议改用向量 - 这是在 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++”解决方案。

于 2013-01-22T13:12:26.047 回答
-1

如果您使用的是数组,最好封装它们:

template<typename Type>
class Vector {
    //...
};

标准库附带一个实现:std::vector

于 2013-01-22T13:15:11.480 回答