递归C ++调用中的内存分配

时间:2009-01-07 22:13:28

标签: c++ memory memory-leaks recursion

我在递归C ++程序中分配和释放内存时遇到问题。因此,如果不使用自动内存管理解决方案,我想知道是否有人可以帮助我解决我遇到的内存泄漏问题。

以下代码基本上解释了问题(尽管这是一个人为的例子,请更正我所犯的任何错误或简化。)

用于保存数字值的数字类:

class Number {
    public:
        Number() { value = 1; };
        Number& operator + (const Number& n1) const {
            Number result = value + n1.value;
            return result;
        };
        int value;
};

执行递归的两个函数:

Number& recurse(const Number& v1) {
    Number* result = new Number();
    Number one = Number();
    *result = *result + recurse(one);
    return *result;
}

int main(...) {
    Number answer = Number();
    answer = recurse(result);
}

正如你所看到的那样,recurse函数中分配的内存被泄露了,但我不确定在哪里可以根据递归的性质释放这个内存?

5 个答案:

答案 0 :(得分:12)

问题在于:

Number& operator + (const Number& n1) const {
    Number result = value + n1.value;
    return result;
};

你通过引用返回一个局部变量(result),这是一个很大的NO-NO。局部变量在堆栈上分配,当函数退出时,变量就消失了。返回对局部变量的引用是将指针返回到现在用于其他东西的堆栈中,这将导致很多不良。

您应该做的是按值返回(只需将返回类型从Number&更改为Number)。确保您有适当的复制构造函数,或者编译器自动生成的复制构造函数适合您的需要。这意味着当operator+返回时,它会生成一个副本(通常可以通过优化),并且由于没有涉及指针或引用,因此无法获得损坏的返回值。

要修复内存泄漏,可以使用boost::shared_ptr等智能指针。或者,完全使用沟渠指针和动态内存,只需按recurse()的值返回结果。

答案 1 :(得分:3)

我不明白你为什么要在堆上分配内存开头:

Number& recurse(const Number& v1) {
    Number result;
    Number one;

    // I assume there is a step here to determine if the recursion should stop

    result += recurse(one);
    return result;
}

通过仅在堆栈上分配,可以保证在函数返回时清除变量。

否则我认为你必须使用某种智能指针。

答案 2 :(得分:2)

所以除了返回Adam Rosenfield指出的局部变量的地址之外,我在代码中还看到了其他三个问题。

首先,你的恢复功能永远不会结束。在recurse()的某个时刻,你必须检查一个值,使它不再调用recurse()并返回。这是递归的基本部分。传递的参数v1也没有被使用。

其次,运算符+()实际上不起作用。没有办法将int分配给Number()对象。

第三,在main中传递一个名为result的东西,它永远不会被声明。

忘记这些错误,我假设您要分配堆上的所有对象以避免堆栈溢出,此函数将递归多次,或者使用的实际对象比Number大得多。在这种情况下,通过在recurse()内的堆上分配返回变量,您强制调用者删除返回的对象。因此,在recurse()和main()中调用recurse()之后,您必须删除返回的值。指示调用者的约定是返回指针而不是引用。所以recurse()和main()看起来像这样:

Number* recurse(const Number& v1) {
    Number* result = new Number();
    Number one;
    if(v1.value >= 2) {
        Number temp;
        temp.value = v1.value - 1;
        Number* partialResult = recurse( temp ); //capture the object to delete
        *result = *partialResult + one;
        delete partialResult;                    //delete the object
    }
    return result;
}

int main() {    
    Number result;
    result.value = 15;
    Number *answer;
    answer = recurse(result);
    delete answer;
}

注意:无论实际计算的是什么递归都是荒谬的。我不知道意图是什么,但它只是有用的东西。

答案 3 :(得分:1)

您是否有动态分配内存的原因?

Number recurse(const Number& v1) {
    Number result;
    Number one;
    retun result + recurse(one);
}

另外我注意到你没有使用值v1

但最大的错误是递归有 NO 转义条款 这实际上是无限递归,基本上会耗尽内存。

答案 4 :(得分:0)

聪明的指针是你的朋友。至少快速阅读auto_ptr。

另外,请阅读Adam Rosenfield对您的其他问题的评论(返回对不存在的值的引用)。