使用reinterpret_cast将数据从std :: vector <double>重新整形为指定维度的double**

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)


Mik*_*our 6

显然,你无法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)