我的代码泄露了.我怎么解决它呢?

My code is leaking. How can I solve it?

本文关键字:解决 代码 我的      更新时间:2023-10-16

我的代码正在泄漏。我应该删除数组的某个地方,我在这行中分配的东西:T* out_array = new T[size1+size2];但我不知道在哪里,怎么去。有人能帮帮我吗?

代码:

#include <iostream>
using namespace std;
template <class T>
T* merge(T arr1[], int size1, T arr2[], int size2);
template <class T>
T* merge_sort(T arr[], int n)
{
    if(n < 2){return arr;}
    int mid = n/2;
    T *arr1 = merge_sort<T>(arr,mid);
    T *arr2 = merge_sort<T>(arr+mid,n-mid);
    return merge(arr1, mid, arr2, n-mid);
}
template <class T>
T* merge(T arr1[], int size1, T arr2[], int size2)
{
    int i = 0,j = 0;
    T* out_array = new T[size1+size2];
    while((i < size1) && (j < size2))
    {
        if(arr1[i] >= arr2[j])
        {
            out_array[i+j] = arr2[j];
            ++j;
        }
        else
        {
            out_array[i+j] = arr1[i];
            ++i;
        }
    }
    while(i < size1)
    {
        //copy the reminder
        out_array[i+j] = arr1[i];
        i++;
    }
    while( j < size2)
    {
        out_array[i+j] = arr2[j];
        j++;
    }
    return out_array;
}
int main()
{
    int a[] = {2, 42, 3, 7, 1};
    int *a2 = merge_sort(a,5);
    for (int i = 0; i<= 4 ; ++i) cout << a2[i] << endl;
    delete[] a2;
    return (0);
}

我记得我在一个严重泄漏的应用程序上进行了紧急处理:

  • 需要快速加载的改进
  • 应用程序已经泄漏,尽管不那么严重
  • 已知非回归是不完整的
  • 应用程序从未在valgrind下运行(在valgrind下运行多线程代码具有严格的超时依赖关系是很重要的…)

那么,我做了什么?我使用grep并从代码(*)中删除对new的所有调用。

  • 在c++ 03: delete是一个错误(**)和new是一个代码气味
  • 在c++ 11: deletenew都是一个错误(**)
不足为奇的是,所有的内存泄漏都消失了!

你可以用:

  • std::vector用于动态分配数组
  • std::unique_ptr用于动态分配对象
  • std::shared_ptr在一些罕见和神秘的情况下,对象的实际生命周期遵循复杂的规则

    (*)或者如果它是c++ 11,在c++ 03中,在没有完美转发和可变模板的情况下,拥有make_auto_ptr是不可能的。

    C++03中的

    (**)可能会被认为是编写boost::scoped_ptr(或同等)的专家可能需要它;在c++ 11中,你可以在unique_ptr之上构建任何抽象,因为它是零成本的。

这些正在泄漏:

T *arr1 = merge_sort<T>(arr,mid);
T *arr2 = merge_sort<T>(arr+mid,n-mid);

修复:

template <class T>
T* merge_sort(T arr[], int n)
{
    if(n < 2){return arr;}
    int mid = n/2;
    T *arr1 = merge_sort<T>(arr,mid);
    T *arr2 = merge_sort<T>(arr+mid,n-mid);
    T * res = merge(arr1, mid, arr2, n-mid);
    delete[] arr1;
    delete[] arr2;
    return res;
}

在您尝试解决实现中的内存泄漏问题之前,请考虑这个问题:每次调用merge()时真的有必要为out_array分配内存吗?

我认为答案是否定的,相反,为辅助数组分配内存(与arr大小相同)一旦merge_sort()中就足够了,并将此数组传递给merge()。这种方法可以大大减少内存分配的次数,并且更容易管理内存分配。

如果您想这样分配内存,您应该使用std::unqiue_ptr。把

T* out_array = new T[size1+size2];

std::unique_ptr<T[]> out_array(new T[size1 + size2]);

修改merge_sort签名返回unique_ptr<T[]>,修复arr1和arr2类型,不手动删除。这种方法比使用delete[]要好,因为可以在T的operator =中生成异常。那么,delete[]操作符将永远不会被调用,您仍然会泄漏内存,即使您像Erik的回答那样添加删除。