Tom*_*han 3 c++ arrays multidimensional-array reinterpret-cast c++11
我有一个std::vector<double>包含M*N值,我想将其重塑为一个double**行为类似于double[N][M]多维数组.这些起点和终点可能看起来很奇怪,但不幸的是它们都是由外部库决定的,所以我无能为力.我问这个问题,看看是否有办法完成这个,而不是简单地手动复制所有数据.
我确实读过这个问题,但答案非常好,但它的起点略有不同 - 而不是从那里std::vector<double>开始double**,而是从那里double[]开始double[][].我试图了解那里发生了什么,并将相同的原则应用于我的案例,但我无法让我的代码工作.我该怎么做呢?
const int M = 3;
const int N = 2;
std::vector<double> f = { 0, 1, 2, 3, 4, 5 };
double* f1d = f.data();
// compiles and doesn't crash
// but f2d seems to be unitialized (at least f2d[1][1] is garbage)
// also has the wrong type (double[][] rather than double**)
double (&f2d)[N][M] = reinterpret_cast<double (&)[N][M]>(f1d);
// segfaults when trying to access e.g. f2d[0][0]
double** f2d = reinterpret_cast<double**>(f1d);
Run Code Online (Sandbox Code Playgroud)
最后,我需要将我的数据传递给一个带double**参数的方法,因此以下必须编译并运行没有问题:
#include <iostream>
#include <vector>
void test(int M, int N, double **arr) {
for (int i = 0; i < N; ++i) {
for (int j = 0; j < M; ++j) {
std::cout << arr[i][j] << " ";
}
std::cout << std::endl;
}
};
int main() {
const int M = 3;
const int N = 2;
std::vector<double> f = { 0, 1, 2, 3, 4, 5 };
// whatever I need to do here to get f2d
test(M, N, f2d);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
预期产量:
0 1 2
3 4 5
Run Code Online (Sandbox Code Playgroud)
R. *_*des 13
double**基于A 的"数组"是与实际多维数组完全不同的野兽,即double[N][M].它具有完全不同的布局并存储不同的信息,因此您无法在不存储任何其他信息的情况下执行所需操作.
double**基于a 的"数组"的工作方式是使用两级结构,其中第一级是包含指向各种常规一维数组的指针的数组.连续的多维数组不能直接作为double**基于"数组"的函数,因为带有指针的第一级结构无处可见:a中的各种子数组double[N][M]是从基地址和大小隐含的.
double[3][2]
+----+----+----+----+----+----+
| 00 | 01 | 02 | 10 | 11 | 12 |
+----+----+----+----+----+----+
double**
+------------+------------+
| 0xDEADD00D | 0xDEADBABE |
+------------+------------+
| |
+-----+ |
| |
v |
+----+----+----+ |
| 00 | 01 | 02 | |
+----+----+----+ |
v
+----+----+----+
| 10 | 11 | 12 |
+----+----+----+
Run Code Online (Sandbox Code Playgroud)
所以,现在,这已经不在了,我们理解double**基于"阵列"的工作方式,我们可以开始尝试解决您的问题.
你需要做的double**是通过填充单独的指针数组来自己提供第一级结构,指针指向单个连续数组中的各种地址.
std::vector<double*> index;
index.reserve(M);
for(int i = 0; i < M; ++i) {
index.push_back(&f[i*N]);
}
double** f2d = index.data();
Run Code Online (Sandbox Code Playgroud)
这为您提供了最小的麻烦,并且空间开销最小.它也不执行任何数据副本,因为我们只收集了一堆指向已有存储的指针.
最终得到的布局如下所示:
index
+------------+------------+
| 0xDEADD00D | 0xDEADBABE |
+------------+------------+
| |
+-----+ +---+
| |
v v
+----+----+----+----+----+----+
f | 00 | 01 | 02 | 10 | 11 | 12 |
+----+----+----+----+----+----+
Run Code Online (Sandbox Code Playgroud)
显然,你无法double**从数组中获得有效数据,因为没有double*可指向的数组.您需要将平面数组重新解释为二维数组,而不是指针数组.
第一次尝试几乎是正确的; 但它重新解释了对指针的引用f1d,而不是它指向的数组,作为一个二维数组.取消引用指针并重新解释对数组的结果引用应该有效:
double (&f2d)[N][M] = reinterpret_cast<double (&)[N][M]>(*f1d);
^
Run Code Online (Sandbox Code Playgroud)
或者,您可以重新解释引用而f[0]无需中间指针.
如您所见,使用reinterpret_cast非常容易出错.您可以考虑将向量包装在一个类中,使用访问器函数来执行二维索引所需的算术运算.
更新:如果由于某种原因你真的想要一个double**而不是一个二维数组,你需要自己构建一个指针数组,沿着
std::vector<double*> pointers;
for (i = 0; i < M; ++i) {
pointers.push_back(&f[i*N]);
}
double** f2d = pointers.data();
Run Code Online (Sandbox Code Playgroud)