如何在 C++ 中正确使用动态分配的多维数组 [重复]
Posted
技术标签:
【中文标题】如何在 C++ 中正确使用动态分配的多维数组 [重复]【英文标题】:How to properly work with dynamically-allocated multi-dimensional arrays in C++ [duplicate] 【发布时间】:2016-03-08 18:21:09 【问题描述】:如何在 C++ 中定义动态多维数组?比如二维数组?我尝试使用指向指针的指针,但不知何故失败了。
【问题讨论】:
@JustinMeiners 可能,但问题是如何使用,而不是如何定义。该问题的最高答案得出的结论是错误的。你必须投下大约 550 票,才能有人得到答案,即使是对了一半。 【参考方案1】:首先应该意识到 C++ 中不支持多维数组,无论是作为语言特性还是标准库。所以我们可以在其中做的任何事情都是对它的一些模仿。我们如何模拟二维整数数组?这里有不同的选项,从最不适合到最适合。
不正确的尝试 #1。使用指针指向指针
如果用指向类型的指针来模拟数组,那么肯定应该用指向类型的指针来模拟二维数组吗?像这样?
int** dd_array = new int[x][y];
这是一个编译器错误。没有new [][]
运算符,所以编译器很乐意拒绝。好的,那怎么样?
int** dd_array = new int*[x];
dd_array[0][0] = 42;
编译。在执行时,它会因不愉快的消息而崩溃。出了点问题,但是什么?当然!我们确实为第一个指针分配了内存——它现在指向一个内存块,其中包含 x 个指向 int 的指针。但是我们从来没有初始化那些指针!让我们再试一次。
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]
这给了我们美妙的语法、性能和所有的荣耀。为了让我们的生活稍微好一点,我们甚至可以在一维向量之上构建一个适配器 - 但这留给家庭作业。
【讨论】:
赞成,但值得添加更正确的尝试 4:将一维数组包装在一个对象中,以减少索引数学中的拼写错误的可能性,当它在其他任何地方都可以工作时,你会在一个地方搞砸。 就在那里,最后一句话。离开做作业:) 是否值得为其他维度添加一个示例,例如来自 C# 的人可能想要使用 3 维数组?我以 C# 为例,因为该语言支持多维数组。 在正常情况下,是的,但是对于像这样的自我回答问题,我会包含一个非常基本的包装以确保完整性。除非你打算拍续集:伙计,我的“操作员[][]`呢? 有时有理由使用#2 而不是#3。例如,如果数组非常大,使用#3 增加行数可能会由于 OOM 失败,或者触发大量重新分配和复制;而#2 没有遇到这个问题(即使它重新分配,现有的行仍然存在)以上是关于如何在 C++ 中正确使用动态分配的多维数组 [重复]的主要内容,如果未能解决你的问题,请参考以下文章