Is it possible in c++ for a class to have a member which is a multidimensional array whose dimensions and extents are not known until runtime?

前端 未结 4 1064
攒了一身酷
攒了一身酷 2021-01-14 01:11

I originally asked using nested std::array to create an multidimensional array without knowing dimensions or extents until runtime but this had The XY Problem of trying to a

相关标签:
4条回答
  • 2021-01-14 01:43

    You can solve the problem in at least two ways, depending on your preferences. First of all - you don't need the Boost library, and you can do it yourself.

    class array{
       unsigned int dimNumber;
       vector<unsigned int> dimSizes;
    
       float *array;
    
       array(const unsigned int dimNumber, ...){
         va_list arguments;
         va_start(arguments,dimNumber);
         this->dimNumber = dimNumber;
         unsigned int totalSize = 1;
         for(unsigned int i=0;i<dimNumber;i++)
         {
            dimSizes.push_back(va_arg(arguments,double));
            totalSize *= dimSizes[dimSizes.size()-1];
         }
         va_end(arguments);
         array = new float[totalSize]; 
       };
    
       float getElement(unsigned int dimNumber, ...){
         va_list arguments;
         va_start(arguments,dimNumber);
         unsgned int elementPos = 0, dimAdd = 1;
         for(unsigned int i=0;i<dimNumber;i++)
         {
            unsigned int val = va_arg(arguments,double);
            elementPos += dimAdd * val;
            dimAdd *= dimsizes[i];
         }
         return array[elementPos]
       };
    };
    

    Setting an element value would be the same, you will just have to specify the new value. Of course you can use any type you want, not just float... and of course remember to delete[] the array in the destructor.

    I haven't tested the code (just wrote it straight down here from memory), so there can be some problems with calculating the position, but I'm sure you'll fix them if you encounter them. This code should give you the general idea.

    The second way would be to create a dimension class, which would store a vector<dimension*> which would store sub-dimensions. But that's a bit complicated and too long to write down here.

    0 讨论(0)
  • 2021-01-14 01:46

    Instead of a multidimensional array you could use a 1D-array with an equal amount of indices. I could not test this code, but I hope it will work or give you an idea of how to solve your problem. You should remember that arrays, which do not have a constant length from the time of being compiled, should be allocated via malloc() or your code might not run on other computers. (Maybe you should create a class array for the code below)

    #include <malloc.h>
    
    int* IndexOffset; //Array which contains how many indices need to be skipped per  dimension
    int  DimAmount;   //Amount of dimensions
    int  SizeOfArray = 1; //Amount of indices of the array
    
    void AllocateArray(int* output,         //pointer to the array which will be allocated
                       int* dimLengths,     //Amount of indices for each dimension: {1D, 2D, 3D,..., nD}
                       int dimCount){       //Length of the array above
    
    DimAmount = dimCount;
    int* IndexOffset = (int*) malloc(sizeof(int) * dimCount);
    int temp = 1;
    
    for(int i = 0; i < dimCount; i++){
    
    temp = temp * dimLengths[i];
    IndexOffset[i] = temp; 
    
    }
    
    
    for(int i = 0; i < dimCount; i++){
    
    SizeOfArray = SizeOfArray * dimLengths[i];
    
    }
    
    output = (int*)malloc(sizeof(int) * SizeOfArray);
    
    }
    

    To get an index use this:

    int getArrayIndex(int* coordinates //Coordinates of the wished index as an array (like dimLengths)
                ){
    
    int index;
    int temp = coordinates[0];
    
    for(int i = 1; i < DimAmount; i++){
    
         temp = temp + IndexOffset[i-1] * coordinates[i];
    
    }
    index = temp;
    return index;
    }
    

    Remember to free() your array as soon as you do not need it anymore:

    for(int i = 0; i < SizeOfArray; i++){
    
        free(output[i]);
    
    }
    free(output);
    
    0 讨论(0)
  • 2021-01-14 01:48

    Yes. with a single pointer member.

    A n multidimensional array is actually a pointer. so you can alocate a dynamic n array and with casting, and put this array in the member pointer.

    In your class should be something like this

    int * holder;
    
    void setHolder(int* anyArray){
      holder = anyArray;
    }
    

    use:

    int *** multy = new int[2][1][56];
    yourClass.setHolder((int*)multy);
    
    0 讨论(0)
  • 2021-01-14 01:52

    Just avoid multidimensional arrays:

    template<typename T>
    class Matrix
    {
        public:
        Matrix(unsigned m, unsigned n)
        :   n(n), data(m * n)
        {}
    
        T& operator ()(unsigned i, unsigned j)  {
            return data[ i * n + j ];
        }
    
        private:
        unsigned n;
        std::vector<T> data;
    };
    
    int main()
    {
        Matrix<int> m(3, 5);
        m(0, 0) = 0;
        // ...
        return 0;
    }
    

    A 3D access (in a proper 3D matrix) would be:

    T& operator ()(unsigned i, unsigned j, unsigned k)  { 
        // Please optimize this (See @Alexandre C) 
        return data[ i*m*n + j*n + k ]; 
    }
    

    Getting arbitrary dimensions and extent would follow the scheme and add overloads (and dimensional/extent information) and/or take advantage of variadic templates.

    Having a lot of dimensions you may avoid above (even in C++11) and replace the arguments by a std::vector. Eg: T& operator(std::vector indices). Each dimension (besides the last) would have an extend stored in a vector n (as the first dimension in the 2D example above).

    0 讨论(0)
提交回复
热议问题