在c ++中,类是否有可能拥有一个多维数组的成员,其维度和范围在运行时才知道?

时间:2013-11-26 19:31:50

标签: c++ c++11 multidimensional-array

我最初问过using nested std::array to create an multidimensional array without knowing dimensions or extents until runtime,但是有The XY Problem试图用std :: array来完成它。

问题One-line initialiser for Boost.MultiArrayHow do I make a multidimensional array of undetermined size a member of a class in c++?及其答案提供了一些有用的信息,告诉我们如何使用Boost :: MultiArray来避免在运行时知道维度的范围,但未能证明如何使用一个类成员,可以存储一个数组(在运行时创建),其数据和范围在运行时才会知道。

4 个答案:

答案 0 :(得分:3)

避免使用多维数组:

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;
}

3D访问(在适当的3D矩阵中)将是:

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

获取任意维度和范围将遵循该方案并添加重载(和维度/范围信息)和/或利用可变参数模板。

你可以避免使用很多维度(即使在C ++ 11中)并用std :: vector替换参数。例如:T&amp; operator(std :: vector indices)。 每个维度(除了最后一个)都有一个存储在向量n中的扩展(作为上面2D示例中的第一个维度)。

答案 1 :(得分:1)

是。使用单个指针成员。

n 多维数组实际上是一个指针。所以你可以使用强制转换动态 n 数组,并将此数组放入成员指针中。

在你的课堂上应该是这样的

int * holder;

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

使用:

int *** multy = new int[2][1][56];
yourClass.setHolder((int*)multy);

答案 2 :(得分:1)

您可以通过至少两种方式解决问题,具体取决于您的偏好。首先 - 你不需要Boost库,你可以自己动手。

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]
   };
};

设置元素值将是相同的,您只需指定新值。当然你可以使用你想要的任何类型,而不仅仅是浮动...当然记得在析构函数中delete[]数组。

我没有测试过代码(只是从内存中直接写下来),所以在计算位置时可能存在一些问题,但我相信如果遇到它们你会修复它们。这段代码应该给你一般的想法。

第二种方法是创建一个dimension类,它将存储一个存储子维度的vector<dimension*>。但这有点复杂,而且写得太长了。

答案 3 :(得分:0)

您可以使用具有相同数量索引的1D数组,而不是多维数组。我无法测试此代码,但我希望它可以工作或让您了解如何解决您的问题。您应该记住,编译时没有恒定长度的数组应该通过malloc()分配,或者您的代码可能无法在其他计算机上运行。 (也许你应该为下面的代码创建一个类array

#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);

}

要获取索引,请使用此选项:

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;
}

在您不再需要时,请记住free()您的阵列:

for(int i = 0; i < SizeOfArray; i++){

    free(output[i]);

}
free(output);