0

I have a pointer that points to the beginning of a 1000+ elements array that is initialized as below:

int numElements = 1200;
auto data = std::unique_ptr<float>{new float[numElements]};

Now I want to 'reshape' it into something like a (20,30,20) tensor, so I can access it the way I want (I can still read while it's 1-D as well but it feels weird). I want to access like this:

data[1][10][12] = 1337.0f;

Is there an efficient way of doing this (fast and short code)?

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
huanidz
  • 19
  • 2
  • You could either use a pointer of pointers (of pointers and so on), or write a function that maps multiple-indices to a single index (possibly by wrapping the pointer into a custom class with ```operator[](int...)``` function), or you could use existing libraries for that. – BernieD Sep 19 '22 at 13:23
  • You can treat the shape as a set of strides determining the number of dimensions, and the number of elements you have to skip to get to the next element in a given dimension. See here: https://en.wikipedia.org/wiki/Row-_and_column-major_order. – wohlstad Sep 19 '22 at 13:24
  • 3
    encapsulate it in a class that does the index mapping in an accessor function then you can use `data.at(1,10,12)`. The exact syntax `data[1][10][12]` is possible to achieve but more complicated than necessary – 463035818_is_not_an_ai Sep 19 '22 at 13:30
  • Groundwork has been laid to allow **in the future** the syntax `data[1, 10, 12]`. Maybe as early as C++27. – Eljay Sep 19 '22 at 16:15
  • Do something like [this](https://stackoverflow.com/a/36123944/4581301) or [this](https://stackoverflow.com/a/2076668/4581301). I find the second option more useful for many dimensional arrays, but when it comes to 2D, there's simplicity to the first option that's worth the lack of versatility. – user4581301 Sep 19 '22 at 17:02
  • Your `std::unique_ptr` usage is wrong and will cause UB. You can fix it but a much more natural solution would be to use `std::vector` instead. – n. m. could be an AI Sep 19 '22 at 17:36

1 Answers1

0

In the meantime, this is how I do it...

#include <iostream>
using std::cout;
using std::endl;

#include <vector>
using std::vector;



size_t get_index(const size_t x, const size_t y, const size_t z, const size_t x_res, const size_t y_res, const size_t z_res)
{
    return z * y_res * x_res + y * x_res + x;
}

    

int main(void)
{
    const size_t x_res = 10;
    const size_t y_res = 10;
    const size_t z_res = 10;

    // Use new[] to allocate, and memset to clear
    //float* vf = new float[x_res * y_res * z_res];
    //memset(vf, 0, sizeof(float) * x_res * y_res * z_res);

    // Better yet, use a vector
    vector<float> vf(x_res*y_res*z_res, 0.0f);

    for (size_t x = 0; x < x_res; x++)
    {
        for (size_t y = 0; y < y_res; y++)
        {
            for (size_t z = 0; z < z_res; z++)
            {
                size_t index = get_index(x, y, z, x_res, y_res, z_res);

                // Do stuff with vf[index] here...
            }
        }
    }

    // Make sure to deallocate memory
    // delete[] vf;

    return 0;
}
shawn_halayka
  • 96
  • 1
  • 1
  • 9