如何创建多维数组(矩阵),其维度在运行时确定。
最好的方法似乎是采用建筑尺寸向量和偏移矢量来访问单个元素
这也允许使用初始化列表:
这应该采用在编译时确定的类型矩阵,因此模板有意义
适当使用C ++ 11功能,lambdas的奖励积分
使用示例:
int main(int, char **)
{
static const std::size_t d1{2};
static const std::size_t d2{3};
static const std::size_t d3{4};
multi_vec<std::size_t> q({d1,d2,d3});
for (std::size_t i1=0; i1 < d1; ++i1)
for (std::size_t i2=0; i2 < d2; ++i2)
for (std::size_t i3=0; i3 < d3; ++i3)
q[{i1,i2,i3}]=foo(i1,i2,i3);
for (std::size_t i1=0; i1 < d1; ++i1)
for (std::size_t i2=0; i2 < d2; ++i2)
for (std::size_t i3=0; i3 < d3; ++i3)
std::cout << "{"
<< i1 << ","
<< i2 << ","
<< i3 << "}=> "
<< foo(i1,i2,i3) << "=="
<< q[{i1,i2,i3}]
<< ((foo(i1,i2,i3) == q[{i1,i2,i3}])
? " good" : " ERROR")
<< std::endl;
};
答案 0 :(得分:3)
这实际上是使用lambdas std::for_each
和unique_ptr进行内存管理的好地方:
template <class T>
class multi_vec
{
public:
using param=std::vector<size_t>;
explicit multi_vec(const param& dimensions)
: dim{dimensions}, prod {1}
{
std::for_each(dim.begin(), dim.end(), [this] (std::size_t val)
{
mult.emplace_back(prod);
prod *= val;
} );
ptr.reset(new T[prod]);
}
std::size_t capacity() const { return prod; }
// undefined if elements in lookup != elemenets in dim
// undefined if any element in lookup
// is greater than or equal to corresponding dim element
T& operator[](const param& lookup)
{
return ptr[get_offset(lookup)];
}
const T operator[](const param& lookup) const
{
return ptr[get_offset(lookup)];
}
private:
std::size_t get_offset(const param& lookup) const
{
std::size_t offset=0;
auto mit=mult.begin();
std::for_each(lookup.begin(), lookup.end(), [&offset, &mit] (std::size_t val)
{
offset+=*mit * val;
++mit;
} );
return offset;
}
param dim;
param mult;
std::size_t prod;
std::unique_ptr<T[]> ptr;
};
这使用单维数组进行实际存储,并缓存乘法器以便重用
由于正常的多维数组,例如x[2][3][4]
不限制检查,超出范围被视为未定义,而不是不断检查可能有效的值。同样地,不检查diminsionality的查找,如果需要,可以添加静态成员来检查参数是否有效,就边界或维度而言。
答案 1 :(得分:0)
在这里回答https://stackoverflow.com/a/19725907/2684539:
#include <cstddef>
#include <vector>
template<typename T>
class MultiArray
{
public:
explicit MultiArray(const std::vector<size_t>& dimensions) :
dimensions(dimensions),
values(computeTotalSize(dimensions))
{
assert(!dimensions.empty());
assert(!values.empty());
}
const T& get(const std::vector<size_t>& indexes) const
{
return values[computeIndex(indexes)];
}
T& get(const std::vector<size_t>& indexes)
{
return values[computeIndex(indexes)];
}
size_t computeIndex(const std::vector<size_t>& indexes) const
{
assert(indexes.size() == dimensions.size());
size_t index = 0;
size_t mul = 1;
for (size_t i = 0; i != dimensions.size(); ++i) {
assert(indexes[i] < dimensions[i]);
index += indexes[i] * mul;
mul *= dimensions[i];
}
assert(index < values.size());
return index;
}
std::vector<size_t> computeIndexes(size_t index) const
{
assert(index < values.size());
std::vector<size_t> res(dimensions.size());
size_t mul = values.size();
for (size_t i = dimensions.size(); i != 0; --i) {
mul /= dimensions[i - 1];
res[i - 1] = index / mul;
assert(res[i - 1] < dimensions[i - 1]);
index -= res[i - 1] * mul;
}
return res;
}
private:
size_t computeTotalSize(const std::vector<size_t>& dimensions) const
{
size_t totalSize = 1;
for (auto i : dimensions) {
totalSize *= i;
}
return totalSize;
}
private:
std::vector<size_t> dimensions;
std::vector<T> values;
};
int main()
{
MultiArray<int> m({3, 2, 4});
m.get({0, 0, 3}) = 42;
m.get({2, 1, 3}) = 42;
for (size_t i = 0; i != 24; ++i) {
assert(m.computeIndex(m.computeIndexes(i)) == i);
}
return 0;
}
答案 2 :(得分:0)
你使用C.老实说,C&C的动态数组优于C ++提供的任何东西。以下是3D数组的代码:
//Allocation, the type needs some effort to understand,
//but once you do understand it, this is easy:
int width = 7, height = 8, depth = 9;
int (*array)[height][width] = malloc(depth*sizeof(*array));
//Filling, completely natural...
for(int z = 0; z < depth; z++) {
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
array[z][y][x] = 42;
}
}
}
//Deallocation, trivial...
free(array);
3D数组不过是2D阵列的一维数组(依次是1D数组的1D数组),因此您将指针*array
声明为整数的二维数组{{1} },并为int (...)[heigh][width]
这样的元素depth
分配空间。这完全类似于使用malloc(depth*sizeof(*array))
创建一维数组。其余的是数组指针衰变魔法。
这适用于C,因为C允许数组类型包含动态大小(自C99起)。它就像在声明点定义两个具有声明大小的常量一样。另一方面,C ++仍然坚持数组大小是编译时常量,因此无法允许动态大小的多维数组。