There is an updated version of this code with some of the recommended changes made here.
I have created an implementation of a multi-dimensional array which utilizes a single continuous memory buffer to improve cache locality. My intention is for this to behave in a similar way to a multi-dimensional vector in c++, and so I have overloaded Tensor::operator[]
to return another Tensor
object of dimension one less, which can then be indexed again with Tensor::operator[]
. There is a base template specialization for the case where the dimension count is 1. Please give me some tips on how this implementation can be improved.
My main concerns with the code are that I use raw malloc and free statements, however I am not quite sure how I could implement this efficiently without using raw pointers and mallocs as I do not want to have to copy memory in the Tensor::operator[]
function. Also I am not using the c++ equivalents of new
and delete
as they do not have an analogue to realloc
.
#include <iostream>
template<typename Ty, size_t N>
class Tensor
{
private:
Ty *data;
size_t *offset;
bool owner;
public:
Tensor() :
data(nullptr), offset((size_t*)malloc((N+1)*sizeof(size_t))), owner(true)
{}
Tensor(Ty *data, size_t *offset) :
data(data), offset(offset), owner(false)
{}
~Tensor()
{
if (owner)
{
free(offset);
free(data);
}
}
Tensor<Ty, N-1> operator[] (size_t i)
{
return Tensor<Ty, N-1>(&data[i*offset[N-1]], offset);
}
void resize(size_t* size)
{
if (!owner)
{
std::cerr << "cannot resize - memory is not owned" << std::endl;
return;
}
offset[0] = 1;
for (size_t i = 1; i <= N; ++i)
{
offset[i] = offset[i-1]*size[N-i];
}
data = (Ty*)realloc(data, offset[N] * sizeof(double));
}
};
template<typename Ty>
class Tensor<Ty, 1>
{
private:
Ty *data;
size_t len;
bool owner;
public:
Tensor() :
data(nullptr), len(0), owner(true)
{}
Tensor(Ty *data, size_t *offset) :
data(data), len(offset[1]), owner(false)
{}
~Tensor()
{
if (owner)
{
free(data);
}
}
Ty &operator[](size_t i)
{
return data[i];
}
void resize(size_t* size)
{
if (!owner)
{
std::cerr << "cannot resize - memory is not owned" << std::endl;
return;
}
len = size[0];
data = (Ty*)realloc(data, len*sizeof(double));
}
};