Answering Questions.
I need to allocate n-dimensional arrays of type T, currently I am using the following functions. Is there a better way to do this?
Yes. Create a class that wraps the 2/3 D array in such a way that memory management is done correctly in an exception safe manner.
You may need the raw pointer for interfacing with other libraries but that does not need to mean you should actively manage the pointer. You need to wrap these in a class so all the memory management for you but provide access to the RAW pointer for situations when you need it.
Example:
template<typename T>
class Array3D
{
private:
static T*** allocate_3d_array(std::size_t nx, std::size_t ny, std::size_t nz)
{
T*** A = new T**[nx];
for(std::size_t i = 0; i < nx; ++i)
{
A[i] = new T*[ny];
for(std::size_r j(0); j < ny; ++j)
{
A[i][j] = new T[nz];
for(std::size_t k(0); k < nz; ++k)
{
A[i][j][k]= 0.;
}
}
}
return A;
}
static void release_3d_array(T*** A, std::size_t nx, std::size_t ny, std::size_t nz)
{
for (std::size_t i = 0; i < nx; ++i)
{
for (std::size_t j = 0; j < ny; ++j)
{
delete[] A[i][j];
}
delete[] A[i];
}
delete[] A;
}
T*** data;
std::size_t xSize;
std::size_t ySize;
std::size_t zSize;
public:
Array3D(std::size_t xSize, std::size_t ySize, std::size_t zSize)
: data(allocate_3d_array(xSize, ySize, zSize)
, xSize(xSize)
, ySize(ySize)
, zSize(zSize)
{}
~Array3D()
{
release_3d_array(data, xSize, ySize, zSize);
}
// Disable Copy for now
Array3D(Array3D const&) = delete;
Array3D& operator=(Array3D const&) = delete;
// Disable Move for now
Array3D(Array3D&&) = delete;
Array3D& operator=(Array3D&&) = delete;
// Allow access to the underlying data when calling C function.
operator T***()
{
return data;
}
};
Now you can create a 3D array where the memory is correctly managed at all times (so no leaks). When you pass the data to a C function it will convert itself to a T***
so that it can be used (I am assuming that the C functions are non owning and will thus not destroy the array and the object is in the same thread and will thus live as long as the function call).
If you want to use operator[]
to access the object See below were I have linked to a stackoverflow article.
Copy is probably not something you want with a 3D array. But if you need it you will need to implement the appropriate functions above.
Move is an advanced form of copy. don't use until you understand move semantics. Again you will need to implement the above functions.
Also, ideally I would like to allocate a 1-D array and access that as a N-D array but I could not figure out a better way of doing that.
Yes this would makes memory usage more effecient so would be the preferred technique to implement a multidimensional arrya. I refer you to an article I have written on SO that points you in the correct direction.
See: How to overload array index operator for wrapper class of 2D array? for an example.
Using existing matrix library is not an option as I want access to raw pointers.
To be honest I am bit surprised by this statement. In my mind this is a requirement of any library that wants to interface with C libraries. Not having this ability is shocking. Maybe you missed it. What library were you thinking of using?
Your current style is definitely lacking in relation to C++. The way you have implemented this provides no benefits to using C++ over C.
Generic Review
I see no need for the template type Ti
template <class T, class Ti>
T*** allocate_3d_array(Ti nx, Ti ny, Ti nz){
In my mind this is always an integer type. Pick one. If you did this for some specific reason that I have not deduced then this should be pointed out in the comments of the code (if it is not obvious to me then I don't think anybody else got it).
Use zero initialization.
new T; // Alocates memory for T but does default initialization.
// for POD types this means nothing is done and the value is
// indeterminate.
new T();// Allocates memory for T but does zero initialization.
// for pod types it means the values have zero.
A[i][j] = new T[nz];
for(Ti k(0); k < nz; ++k){
A[i][j][k]= 0.;
}
// Can be replaced with:
A[i][j] = new T[nz]();