内存分配的专用功能会导致内存泄漏吗?

时间:2009-04-08 17:07:10

标签: c++ memory-leaks

Hy all,

我认为下面这段代码会产生内存泄漏?

    /* External function to dynamically allocate a vector */
    template <class T>
            T *dvector(int n){
            T *v;

            v = (T *)malloc(n*sizeof(T));

            return v;
    }


    /* Function that calls DVECTOR and, after computation, frees it */
    void DiscontinuousGalerkin_Domain::computeFaceInviscidFluxes(){
            int e,f,n,p;
            double *Left_Conserved;

            Left_Conserved = dvector<double>(NumberOfProperties);

            //do stuff with Left_Conserved
            //

            free(Left_Conserved);

            return;
    }

我认为,通过将指针传递给DVECTOR,它会分配它并返回正确的地址,以便 free(Left_Conserved)成功解除分配。但是,似乎并非如此。

注意:我还使用 new / delete 替换 malloc / free 进行了测试,但未成功。

我有一个用于分配二维数组的类似代码。我决定管理这样的矢量/数组,因为我经常使用它们,我也想了解使用C ++进行更深入的内存管理。

所以,我非常希望保留一个外部函数来为我分配向量和数组。这里有什么可以避免内存泄漏?

修改

我一直在使用DVECTOR函数来分配用户定义的类型,所以这可能是一个问题,我想,因为我没有调用构造函数。

即使在我释放Left_Conserved向量之前的代码段中,我也想以其他方式分配一个向量并将其保持为“open”以通过其指针通过其他函数进行评估。如果使用BOOST,它会在函数结束时自动清除分配,所以,我不会得到一个带有BOOST的“公共”数组,对吗?我想用NEW很容易解决这个问题,但对于矩阵来说,更好的方法是什么呢?

我刚刚发现我将指针作为参数传递给其他函数。现在,BOOST似乎没有那么多享受它,并且编译以错误退出。

所以,我仍然需要一个指向向量或矩阵的指针,它接受用户定义的类型,它们将作为参数传递给其他函数。矢量(或矩阵)很可能在外部函数中分配,并在另一个合适的函数中释放。 (我只是不想复制循环和新的东西,以便在代码中的任何地方分配矩阵!)

以下是我想做的事情:

    template <class T>
    T **dmatrix(int m, int n){
            T **A;

            A = (T **)malloc(m*sizeof(T *));
            A[0] = (T *)malloc(m*n*sizeof(T));

            for(int i=1;i<m;i++){
                    A[i] = A[i-1]+n;
            }

            return A;
    }


    void Element::setElement(int Ptot, int Qtot){

            double **MassMatrix;

            MassMatrix = dmatrix<myT>(Ptot,Qtot);

            FillInTheMatrix(MassMatrix);

            return;
    }

6 个答案:

答案 0 :(得分:7)

那里没有内存泄漏,但你应该使用new / delete []而不是malloc / free。特别是因为你的功能是模板化的。

如果您想要使用具有非平凡构造函数的类型,则基于malloc的函数会被破坏,因为它不会调用任何构造函数。

我只需要这样做就可以取代“dvector”:

void DiscontinuousGalerkin_Domain::computeFaceInviscidFluxes(){
        double *Left_Conserved = new double[NumberOfProperties];

        //do stuff with Left_Conserved
        //

        delete[] Left_Conserved;
}

它在功能上是等效的(除了它可以调用其他类型的构造函数)。它更简单,需要更少的代码。此外,每个c ++程序员都会立即知道发生了什么,因为它不涉及额外的功能。

更好的是,使用智能指针完全避免内存泄漏:

void DiscontinuousGalerkin_Domain::computeFaceInviscidFluxes(){
        boost::scoped_array<double> Left_Conserved(new double[NumberOfProperties]);

        //do stuff with Left_Conserved
        //
}

许多聪明的程序员都喜欢说“最好的代码是必须编写的代码”

编辑:为什么您认为您发布的代码会泄露内存?

编辑:我看到你对其他帖子的评论

  

在代码执行命令顶部显示   分配内存增长   无限期!

这可能完全正常(或可能不是),具体取决于您的分配模式。通常,堆的工作方式是它们经常增长,但不会经常缩小(这有利于后续分配)。完全对称的分配和释放应该允许应用程序稳定在一定的使用量。

例如:

while(1) {
    free(malloc(100));
}

不应该导致持续增长,因为堆很可能为每个malloc提供相同的块。

所以我的问题是。它是“无限期地”增长还是只是不缩小?

修改

您已询问如何处理2D阵列。就个人而言,我会用一个类来包装细节。我要么使用一个库(我相信boost有一个n-dimmentional数组类),或者你自己滚动应该不会太难。这样的事情就足够了:

http://www.codef00.com/code/matrix.h

用法是这样的:

Matrix<int> m(2, 3);
m[1][2] = 10;

使用像operator()这样的东西来索引矩阵包装类在技术上更有效,但在这种情况下,我选择模拟本机数组语法。如果效率非常重要,那么它可以像本机数组一样高效。

编辑:另一个问题。你在开发什么平台?如果它是* nix,那么我会建议valgrind来帮助查明你的内存泄漏。由于您提供的代码显然不是问题。

我不知道,但我确信Windows也有内存分析工具。

编辑:如果您坚持使用普通的旧数组,那么为什么不将它分配为单个连续的块并对索引进行简单的数学运算,如下所示:

T *const p = new T[width * height];

然后访问一个元素,只需这样做:

p[y * width + x] = whatever;

这样你就可以在指针上做一个delete[],无论它是1D还是2D数组。

答案 1 :(得分:1)

没有可见的内存泄漏,但是使用这样的代码存在内存泄漏的高风险。尝试始终将资源包装在对象(RAII)中。 std :: vector完全符合你的要求:

void DiscontinuousGalerkin_Domain::computeFaceInviscidFluxes(){
        int e,f,n,p;
        std::vector<double> Left_Conserved(NumOfProperties);//create vector with "NumOfProperties" initial entries

        //do stuff with Left_Conserved
        //exactly same usage !
        for (int i = 0; i < NumOfProperties; i++){//loop should be "for (int i = 0; i < Left_Conserved.size();i++)" .size() == NumOfProperties ! (if you didn't add or remove any elements since construction
             Left_Conserved[i] = e*f + n*p*i;//made up operation
        }
        Left_Conserved.push_back(1.0);//vector automatically grows..no need to manually realloc
        assert(Left_Conserved.size() == NumOfProperties + 1);//yay - vector knows it's size
        //you don't have to care about the memory, the Left_Conserved OBJECT will clean it up (in the destructor which is automatically called when scope is left)
        return;
}

编辑:添加了一些示例操作。你真的应该读一下STL容器,它们是值得的!
编辑2:2d你可以使用:

std::vector<std::vector<double> >
像评论中建议的人一样。但使用2d有点棘手。你应该首先研究1d案例以了解发生了什么(扩大向量等)。

答案 2 :(得分:0)

我在这段代码中没有看到内存泄漏。

如果你在c ++上编写程序 - 使用new / delete而不是malloc / free。

为避免可能的内存泄漏,请使用智能指针或stl容器。

答案 3 :(得分:0)

不,只要你在调用dvector模板和free之间没有做任何激烈的事情,你就不会泄露任何记忆。什么告诉你有内存泄漏?

请问,为什么您选择创建自己的数组而不是使用vectorlist等STL容器?这肯定会为你节省很多费用。

答案 4 :(得分:0)

如果您将n的否定值传递给dvector会怎样?

也许您应该考虑更改函数签名以将无符号类型作为参数:

template< typename T >
T * dvector( std::size_t n );

另外,作为一种风格问题,我建议您在提供内存分配功能时始终提供自己的内存释放功能。就像现在一样,呼叫者依赖于dvector使用malloc实现的知识(并且free是适当的释放调用)。像这样:

template< typename T >
void dvector_free( T * p ) { free( p ); }

正如其他人所建议的那样,将此作为RAII类会更加强大。最后,正如其他人所建议的那样,有很多现有的,经过时间考验的库可以做到这一点,所以你根本不需要自己动手。

答案 5 :(得分:0)

因此,这里讨论的一些重要概念帮助我解决了代码中泄漏的内存问题。有两个主要的错误:

  • 我的用户定义类型的 malloc 的分配是错误的。但是,当我将其更改为 new 时,泄漏变得更糟,这是因为我的一个用户定义类型的构造函数调用了一个没有参数且没有正确内存管理的外部函数。因为我在构造函数之后调用了该函数,所以处理本身没有错误,只是在内存分配上。所以 new 正确的构造函数解决了一个主要的内存泄漏问题。

  • 另一个漏洞与一个错误的内存释放命令有关,我可以将其与Valgrind隔离(并且有点耐心以正确获取其输出)。所以,这是错误(而且,请不要称我为白痴!):

    if (something){
            //do stuff
            return;    //and here it is!!!  =P
    }
    free();
    return;
    

正如我所理解的那样,RAII会避免错误编程。我实际上还没有将它改为std :: vector或boost :: scoped_array编码,因为我仍然不清楚是否可以将它们作为参数传递给其他函数。所以,我仍然必须小心 delete []

无论如何,内存泄漏消失了(现在......)= D