Why can't a multidimensional array be allocated with one new call in C++?
In C++ you can easily allocate one dimensional array like this:
T *array=new T[N];
And you can delete it with one statement too:
delete[] array;
The compiler will know the magic how to deallocate the correct number of bytes.
But why can't you alloc 2-dimensional arrays like this?
T *array=new T[N,M];
Or even like this?
T *array=new T[N,M,L];
If you want a multidimensional you have to do it like this:
T **array=new T*[N];
for(int i=0;i<N;i++) array[i]=new T[M];
If you want a fast program that uses matrices (matrix operations, eigenvalue algorithms, etc...) you might want to utilize the cache too for top performance and this requires the data to be in the same place. Using vector<vector<T> >
is the same situation. In C you can use variable length arrays on the stack, but you can't allocate them on the heap (and stack space is quite limi开发者_StackOverflow中文版ted), you can do variable length arrays in C++ too, but they won't be present in C++0x.
The only workaround is quite hackish and error-phrone:
T *array=new T[N*M];
for(int i=0;i<N;i++)
for(int j=0;j<M;j++)
{
T[i*N+j]=...;
}
Your workaround of doing T *array=new T[N*M];
is the closest you can get to a true multi-dimensional array. Notice that to locate the elements in this array, you need the value of M
(I believe your example is wrong, it should be T[i*M+j]
) which is known only at run-time.
When you allocate a 2D array at compile-time, say array[5][10]
, the value 10
is a constant, so the compiler simply generates code to compute i*10+j
. But if you did new T[N,M]
, the expression i*M+j
depends on the value of M
at the time the array was allocated. The compiler would need some way to store the value of M
along with the actual array itself, and things are only going to get messy from here. I guess this is why they decided not to include such a feature in the language.
As for your workaround, you can always make it less "hackish" by writing a wrapper class that overloads operator ()
, so that you could do something like array(i, j) = ...
.
Because multidimensional array is something different then array of arrays/pointers.
use std::vector
Why can't a multidimensional array be allocated with one new call in C++?
Because when the ISO wrote the C++ language standard, they didn't decide to add that feature to the language. I don't know why they decided not to.
If you don't like that, you can create helper functions to allocate/free multidimensional arrays, or you can switch to a language like C# or Java that does support easily allocating multidimensional arrays.
What you can do, however, is allocate an object containing a two-dimensional array off the heap. I would just write a wrapper class for it.
I was thinking about this question last night, and this solution came to me.
T * raw = new T[N*M];
T ** array = new T*[N];
for(int i=0; i<N; i++)
array[i] = raw + i * M;
Now "array" acts just like a contiguous static sized two dimensional array. You just have to take care of deleting both the raw array, and the multi-dimensional array.
I would recommend that you use a Boost::multi_array, from the library of the same name, which provides a simple interface to a multidimensional array. It can be allocated in one line, and at a sufficiently high optimization level is usually as fast as a native array.
Here's some example code from the library's website:
#include "boost/multi_array.hpp"
#include <cassert>
int
main () {
// Create a 3D array that is 3 x 4 x 2
typedef boost::multi_array<double, 3> array_type;
typedef array_type::index index;
array_type A(boost::extents[3][4][2]);
// Assign values to the elements
int values = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
A[i][j][k] = values++;
// Verify values
int verify = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
assert(A[i][j][k] == verify++);
return 0;
}
Because the comma is an operator.
int a = (3, 5, 7, 9);
The program will evaluate 3, discard the result, evaluate 5, discard the result, evaluate 7, discard the result, evaluate 9, and assign it to a.
Hence the syntax you are looking for can't be use, and retain backward compatibility to c.
精彩评论