用新的/声明的指针数组声明的普通[] [] []数组
问题:内存中不连续,每个单独的数组在内存中都有其独立的位置
...
是的,始终使用#define声明大小。 –不可思议
是的,C ++多维数组很棘手,并且非常擅长使C ++代码不可读。实际上,如果在编译时就知道大小,则可以创建静态多维数组,因此可以将其分配为连续的内存块。
int main()
{
int arr[100][200][100]; // allocate on the stack
return 0;
}
问题是如何在堆上分配它...没问题,只需将其包装到一个结构中,然后在堆上分配该结构即可。
#include <memory>
struct Foo
{
int arr[100][200][100];
};
int main()
{
auto foo = std::make_unique<Foo>(); // allocate on the heap
auto& arr = foo->arr;
arr[1][2][3] = 42;
return 0;
}
std::make_unique
调用在堆上分配Foo
,并保证将释放内存。另外,您可以用几乎为零的样板代码访问Foo
内部和外部的数组。很好!
,
正确的方法是编写/使用多维数组类。多维数组是整个计算机科学的基本对象,并且(IMO)疯狂的STL从未包括对多维数组的一流支持。在内部,该类应在堆上分配一个1d数组(用于运行时大小的数组),并进行算术运算以将多维索引转换为1d索引。
Eigen是进行数值工作的理想选择;不确定对非数字类型的多维数组有多大用处。
,
如果除第一个维之外的所有维都是编译时常量(无论第一个维是否为编译时常量),只需编写new T[x][Y][Z]
或(更安全地)编写std::make_unique<T[][Y][Z]>(x)
。结果是连续的,如果合适的话,编译器将有机会应用诸如移位之类的技巧而不是乘法。对于这样的实体,您不能做的就是将其作为指针和大小传递给需要一维数组的函数:
f(&a3[0][0][0],x*Y*Z); // undefined behavior
因为指针算术仅在一个T[]
数组(此处为a3[0][0]
的数组T[Z]
)中定义。
如果第一维也恒定,则可以使用嵌套的std::array
(实际上没有额外的内存开销)
struct A3 {
T a[X][Y][Z];
};
每种方法都有一个优点,它可以通过 value 传递和返回并用作标准容器元素。这样的对象当然也可以通过引用传递,也可以使用“数组参数”:
T f(A3 &a3) {
return a3.a[0][0][1]+a3.a[0][1][0]+a3.a[1][0][0];
}
T g(T a[][Y][Z]) {
return a[0][0][1]+a[0][1][0]+a[1][0][0];
}
请注意,g
的参数类型实际上是T (*)[Y][Z]
,因此可以省略第一个界限。如果有
A3 *a3;
您将其称为
f(*a3);
g(a3->a);
但这只是标准的指针用法,与数组类型或堆分配无关。
,
内存几乎总是一维的。我们认为语言中的多维数组是编译器产生的一种错觉。
让我们举个例子。
int numbers_1[10];
int numbers_2[2][5];
从处理器的角度来看,这两者都为10个整数分配了足够的存储空间,并且保留类型安全性(在C / C ++中可能如此)。确实,您可以通过类型转换指针将其转换为任意一个维度,将其视为任意一个维度。
numbers_1[0] == ((int**)numbers_1)[0][0];
这个表达式成立,对所有10个元素来说都是如此。
数组的存储类无关紧要,它们实际上只是一维。
此外,如果您了解图灵机的工作原理,我相信这会有所帮助。即使在UTM中,磁带也是一维的,这是我们拥有的功能最强大的理论机器。
本文链接:https://www.f2er.com/3016912.html