【问题标题】:How to delete an array that a function returns如何删除函数返回的数组
【发布时间】:2017-03-22 18:23:53
【问题描述】:

我是 C++ 新手,我遇到了一个小的内存泄漏问题。我的程序结构很简单,如下图,虽然我省略了与问题无关的部分。

int** foo(int sizeOfArray){

     int** arrayToReturn = new int*[sizeOfArray];

     for (int i = 0; i < sizeOfArray; i++) {
           arrayToReturn[i] = new int[2];
     }
     return arrayToReturn;
}

int main() {       
    a = someNumber;                // 'a' can be any value ( < 64)
    int** someArray = foo(int a);
    // Do stuff with someArray
}

所以本质上,它调用了一个返回数组数组的函数。我的问题是,当我的程序调用这个函数数千次时,它们会导致内存泄漏,因为我使用的是 NEW,所以我需要使用 delete。我只是不确定如何删除数组,因为我需要在主函数中使用它们,所以我不能在函数 foo 中删除它们,但是之后如何删除它们?我尝试只删除someArray,但是从arrayToReturn[i] = new int[2] 行用完的内存永远不会被释放。

希望这是有道理的,如果这是一个愚蠢的问题,我很抱歉,感谢阅读!

【问题讨论】:

  • 不要使用原始指针,使用像 'std::unique_ptr' 这样的 c++ 指针类。此外,如果这就是你真正想要的,那么使用 std::vector<:pair int>> 而不是自己做也会好得多
  • 我从未使用过vector或unique_ptr,一旦超出范围,它们会自行释放吗?它们易于学习使用吗?有没有办法用原始指针实现我想要的?
  • @MatthewFennell 两者都比学习手动内存管理容易得多。
  • @MatthewFennell:编译器会插入对复制构造函数和析构函数的正确调用,使它们的使用像使用整数一样简单。然后,两个析构函数(vector 和 unique_ptr)都会清理托管资源。使用原始指针,您必须调用正确的析构函数,事实证明人类不像编译器那样擅长记账。

标签: c++ arrays memory heap-memory


【解决方案1】:

要完全删除数组,包括其中的子数组,您可以执行以下操作:

// Assuming we have an array called 'array'
int** array = foo(bar);

// Iterate through all the sub-arrays and delete them
for (int i = 0; i < sizeOfArray; i++) {    
   delete [] array[i];
}

// Delete the primary array
delete [] array;

此代码存在一些样式问题,有些人可能会尝试告诉您不要使用原始指针,但我只是想以直截了当的方式为您回答这个问题。

这基本上与您用于创建数组的操作顺序相反。首先创建外部数组,然后迭代并创建子数组,删除需要先删除子数组,然后删除最外面的数组。

【讨论】:

    【解决方案2】:

    这不是很好的 C++,我不记得上次在数组上使用 new 和 delete 是很久以前的事了。但是,当你学习的时候,你需要知道它是如何工作的,所以继续努力,祝你好运!

    这是ints 数组的相关代码:

    int* foo = new int[20];
    // free the array
    delete [] foo;
    

    【讨论】:

    • 这并不能解决我的问题。当我不再在创建数组的范围内时,我需要一种删除数组的方法。
    • 请注意,OP的问题是关于一个锯齿状数组,所以这个答案有点简单。
    • 是的,设计使然。这对我来说就像家庭作业。如果您有指向数组开头的指针,您可以使用 delete [] ptr 删除整个数组。知道这一点后,您可以将其应用于数组数组或其他任何内容。
    • @MatthewFennell 作为范围是无关紧要的。如果您有指向数组开头的指针,则可以将其删除。这不好,惯用的 C++
    【解决方案3】:

    对于初学者,您必须以与分配相反的顺序删除指针。

    你可以编写一个函数来完成这个任务

    void free( int **array, int sizeOfArray )
    {
        for ( int i = 0; i < sizeOfArray; i++ ) 
        {
            delete [] array[i];
        }
    
        delete [] array;
    }
    

    或者它甚至可以定义为

    void free( int ** &array, int sizeOfArray )
    {
        for ( int i = 0; i < sizeOfArray; i++ ) 
        {
            delete [] array[i];
        }
    
        delete [] array;
    
        array = nullptr;
    }
    

    您可以使用在标头&lt;vector&gt; 中声明的标准类std::vector,而不是自己分配和释放内存

    例如你的数组可以这样定义

    std::vector<std::vector<int>> array( sizeOfArray, std::vector<int>( 2 ) );
    

    在这种情况下,您无需担心释放内存。

    【讨论】:

    • 不是只有二维数组才需要 for 循环吗?
    • @APA 其实是模拟了一个二维数组。
    • 对于一维数组,不会删除 [] arr;够了吗?
    • 为什么你需要一个指向引用指针的指针?
    • @APA 请重新阅读问题和答案。
    【解决方案4】:

    这个问题的标准解决方案是一开始就不要走这条路。

    std::vector is the one stop shop for all your dynamic array needsstd::array stands in for the static array。总之,我们得到了一个很好的二维数组,它恰好在内存中是连续的,并且会在它超出范围时被释放。

    #include <vector>
    #include <array>
    
    std::vector<std::array<int, 2>> foo(int sizeOfArray){
    
        return std::vector<std::array<int, 2>>(sizeOfArray);
    }
    
    int main() {
        int a = 50; // your number here
        std::vector<std::array<int, 2>> someArray = foo(a);
        // Do stuff with someArray
    
    
    } //someArray goes out of scope and is destoyed, freeing all of the allocated memory
    

    【讨论】:

      【解决方案5】:

      参见“deleteArray”函数。您几乎必须先删除子数组。然后删除顶层数组。学习记忆管理是一项很好的技能。一旦您学习了内存管理(使用“new”和“delete”),您应该了解 STL 容器。在实践中,人们会使用 STL。

      我还添加了一个打印功能,这样你就可以看到它的样子了。

      #include <iostream>
      
      int** foo(int sizeOfArray){
          int** arrayToReturn = new int*[sizeOfArray];
      
          for (int i = 0; i < sizeOfArray; i++) { 
              arrayToReturn[i] = new int[2];
              for (int j = 0; j < 2; j++){
                  arrayToReturn[i][j] = j;
              } 
          } 
      
          return arrayToReturn;
      }
      
      void printArray(int **array, int sizeOfArray){
          for(int i = 0; i < sizeOfArray; i++){
              for(int j = 0; j < 2; j++){
                  std::cout << array[i][j] << " "; 
      
              } 
              std::cout <<  std::endl;
          } 
      }
      
      void deleteArray(int **array, int sizeOfArray){
          // Do the inverse of foo
          // Delete the sub arrays (ones with size 2)
          for(int i = 0; i < sizeOfArray; i++){
              delete [] array[i];
          }
      
          // Then delete the entire array
          delete [] array;
      }       
      
      int main(){
          int a = 34;
          int **someArray = foo(a);
          printArray(someArray, a);
      
          std::cout << someArray << std::endl;
      
          // Delete pieces of memory
          deleteArray(someArray, a);
      
          // Readability as well. Set our local reference to NULL
          // Also, will make sure we can't use someArray elsewhere
          someArray = NULL;
      
      
          // This 'printArray' call would cause a segfault 
          // printArray(someArray, a);
      
          return 0;
      }  
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-11-12
        • 2021-12-11
        • 2019-05-13
        • 2011-03-29
        • 2023-01-28
        • 1970-01-01
        • 2019-10-01
        相关资源
        最近更新 更多