C++:如何安全地释放堆分配的向量数组?

Posted

技术标签:

【中文标题】C++:如何安全地释放堆分配的向量数组?【英文标题】:C++ : How to safely deallocate a heap-allocated array of vectors? 【发布时间】:2020-12-13 17:14:20 【问题描述】:

我目前正在处理需要我制作向量数组的代码(我是 C++ 新手 - 如果这是一个绝对糟糕的想法,我将非常感谢反馈)。

假设我在堆上为我的向量分配内存,如下所示:

#include <iostream>
#include <vector>
#include <random>

int main() 
    typedef std::vector<double> doubleVec;
    long N = 1000;
    long M = 1000;

    doubleVec *array = new doubleVec[N];

    for (long i = 0; i < N; i++) 
        doubleVec currentVec = array[i];
        currentVec.resize(M);
        for (long j = 0; j < M; j++)
            currentVec[j] = std::rand();
    
    // ... do something with the data structure

   delete [] array;

当我完成了我需要对数据做的所有事情后,我应该如何安全地释放这个数据结构?

注意:我在最初的帖子中做错了一些我不打算成为讨论焦点的事情(未初始化的变量,没有调整矢量大小等)。我现在修好了。谢谢大家指出这些。

【问题讨论】:

使用智能指针,例如:std::unique_ptr 而不是原始指针,但“要点”是“为什么需要一堆指针”? 你不使用std::vector&lt;std::vector&lt;double&gt;&gt;代替array的原因是什么? 你用new[]创建的;你用delete[] 销毁它。不要想太多。 【参考方案1】:

问题不在于deallocating,而在于每个向量分配。您在代码中的哪个位置使用 M 值(访问元素时除外)?您的代码中还有其他问题,因此快速解决方法是:

    for (long i; i < N; i++) 
        doubleVec &currentVec = array[i];
        currentVec.resize(M);
        for (long j; j < M; j++)
            currentVec[j] = std::rand();
    

请特别注意currentVec 是一个引用:否则不会在array 中存储任何更改。

无论如何,每个人都会遇到的主要问题是:为什么需要一个向量数组?.. 向量向量是一个更优雅的解决方案。

更新:我错过了您忘记初始化ij 的事实。除了初始化它们的建议之外,我还建议使用 auto 关键字,这将使变量无法保持未初始化:

    for (auto i=0UL; i < N; i++) 
        doubleVec &currentVec = array[i];
        currentVec.resize(M);
        for (auto j=0UL; j < M; j++)
            currentVec[j] = std::rand();
    

0UL 表示 unsigned long 类型的零。

【讨论】:

因为我的判断一直严重失误。【参考方案2】:

如果这是一个绝对糟糕的想法,我将非常感谢您的反馈)。

是的,这是一个非常糟糕的主意。具体来说,拥有裸指针是个坏主意。与其手动分配动态数组,不如使用std::vector之类的容器。

如何安全地释放堆分配的向量数组?

通过使用向量而不是手动动态数组。在这种情况下,一个简单的解决方案是使用向量的向量。

一个可能更好的解决方案是分配一个大小为 1000*1000 的双精度平面向量,其中每个“子向量”的元素一个接一个。这需要一些简单的数学运算来计算子向量的索引,但在大多数用例中更快。


其他说明:

typedef std::vector<double> doubleVec;

避免通过像这样隐藏类型名称来混淆程序。

 for (long j; j < M; j++)
      ^^^^^^

您未初始化此变量。以后使用不确定值时,程序的行为是不确定的。

此外,您忘记包含定义 std::vectorstd::rand 的标准标头。

我遇到了段错误

请参阅关于您实际上并未向数组中的向量添加任何元素的其他答案。这和未初始化的变量是段错误的最可能原因,具体取决于“做某事”的作用。

【讨论】:

有什么更好的选择?我应该只做一个数组数组还是一个向量向量? (我稍微意识到这是一个愚蠢的问题) @Gromulus-Romulus 见第二段。 向量向量会更好吗,因为这样我就不必考虑指针了?我可以通过引用任何会使用它的函数来传递吗? Seg 错误现已修复。这些都是因为我没有正确初始化变量。

以上是关于C++:如何安全地释放堆分配的向量数组?的主要内容,如果未能解决你的问题,请参考以下文章

在堆上“分解” c++ 数组是不是安全?

如何在 C++ 中安全地实现可重用的暂存存储器?

动态分配 SIMD 向量数组是不是安全?

C++ 对象的动态建立 & 释放

如何有效地为现代 C++ 中指向虚拟基类的指针向量分配空间

C++中向量的初始容量