如何在C++中正确处理动态分配的多维数组

How to properly work with dynamically-allocated multi-dimensional arrays in C++

本文关键字:数组 动态分配 正确处理 C++      更新时间:2023-10-16

如何在C++中定义动态多维数组?例如,二维数组?我试着使用指针对指针,但不知怎么的,它失败了。

首先应该意识到,C++中不支持多维数组,无论是作为语言特性还是标准库。所以,我们可以在其中做的任何事情都是对它的模拟。我们如何模拟,比如说,二维整数数组?这里有不同的选择,从最不合适到最合适。

错误的尝试#1。使用指针对指针

如果数组是用指向类型的指针模拟的,那么二维数组肯定应该用指向该类型的指针来模拟吗?像这样的东西?

int** dd_array = new int[x][y];

这是一个编译器错误。并没有new [][]运算符,所以编译器欣然拒绝。好吧,怎么样?

int** dd_array = new int*[x];
dd_array[0][0] = 42;

编译。在执行时,它会崩溃,并发出令人不快的消息。出了问题,但怎么了?当然我们确实为第一个指针分配了内存——它现在指向一个内存块,该内存块包含指向int的x个指针。但我们从未初始化过这些指针!让我们再试一次。

int** dd_array = new int*[x];
for (std::size_t i = 0; i < x; ++i)
   dd_array[i] = new int[y];
dd_array[0][0] = 42;

这不会产生任何编译错误,并且程序在执行时不会崩溃。任务完成了吗?没那么快。请记住,每次调用new时,都必须调用delete。所以,给你:

for (std::size_t i = 0; i < x; ++i)
    delete dd_array[i];
delete dd_array;

现在,这太可怕了。语法很难看,手动管理所有这些指针。。。不。让我们放弃一切,做一些更好的事情。

不太恰当的尝试#2。使用std::vector中的std::vector

好的。我们知道,在C++中,我们不应该真正使用手动内存管理,这里有一个方便的std::vector。那么,也许我们可以做到这一点?

std::vector<std::vector<int> > dd_array;

显然,这还不够——我们从未指定过这些数组的大小。所以,我们需要这样的东西:

std::vector<std::vector<int> > dd_array(x);
for(auto&& inner : dd_array)
    inner.resize(y);
dd_array[0][0] = 42;

那么,现在好吗?没那么多。首先,我们仍然有这个循环,这让人很头疼。更重要的是,我们正在严重损害应用程序的性能。由于每个单独的内部向量都是独立分配的,所以像这样的循环:

int sum = 0;
for (auto&& inner : dd_array)
    for (auto&& data : inner)
       sum += data;

将导致对许多独立分配的内部向量的迭代。由于CPU只会缓存连续内存,所以这些小的独立向量不能完全缓存。不能缓存会影响性能!

那么,我们该如何做对呢?

正确的尝试#3-一维

我们根本没有!当情况需要二维向量时,我们只需通过编程使用一维向量,并使用偏移量访问它的元素!我们就是这样做的:

vector<int> dd_array(x * y);
dd_array[k * x + j] = 42; // equilavent of 2d dd_array[k][j]

这给了我们精彩的语法、性能和所有的荣耀。为了让我们的生活稍微好一点,我们甚至可以在一维向量上构建一个适配器,但这是留给家庭作业的。