简体   繁体   English

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

[英]Memory Allocation in Recursive C++ Calls

I'm having problems allocating and deallocating my memory in a recursive C++ program. 我在递归C ++程序中分配和释放内存时遇到问题。 So without using an automatic memory management solution, I wonder if anyone can help me resolve the memory leak I am experiencing. 因此,如果不使用自动内存管理解决方案,我想知道是否有人可以帮我解决我遇到的内存泄漏问题。

The following code essentially explains the problem (although it's a contrived example, please correct any mistakes or simplifications I've made). 以下代码基本上解释了问题(尽管这是一个人为的例子,请纠正我所犯的任何错误或简化)。

A number class to hold the value of a number: 一个数字类,用于保存数字的值:

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

Two functions to perform the recursion: 执行递归的两个函数:

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);
}

As you can see the memory allocated in the recurse function is leaked, but I'm not sure where I can free up this memory from based on the nature of the recursion? 正如你所看到的那样,recurse函数中分配的内存被泄露了,但我不确定在哪里可以根据递归的性质释放这些内存?

The problem is here: 问题出在这里:

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

You're returning a local variable ( result ) by reference, and that's a big NO-NO. 你通过引用返回一个局部变量( result ),这是一个很大的NO-NO。 Local variables are allocated on the stack, and when the function exits, the variables are gone. 局部变量在堆栈上分配,当函数退出时,变量就消失了。 Returning a reference to a local variable is returning a pointer into the stack that's now being used for something else, and that's going to cause lots of badness. 返回对局部变量的引用是将指针返回到现在用于其他东西的堆栈中,这将导致很多不良。

What you should instead do is return by value (just change the return type from Number& to Number ). 你应该做的是按值返回(只需将返回类型从Number&更改为Number )。 Make sure you have an appropriate copy constructor, or that the compiler's automatically generated copy constructor suits your needs. 确保您有适当的复制构造函数,或者编译器自动生成的复制构造函数适合您的需要。 This means when operator+ returns, it makes a copy (which can often by optimized away), and since there's no pointers or references involved, you can't get a corrupted return value. 这意味着当operator+返回时,它会生成一个副本(通常可以通过优化),并且由于没有涉及指针或引用,因此无法获得损坏的返回值。

To fix your memory leak, you can use smart pointers such as boost::shared_ptr . 要修复内存泄漏,可以使用boost::shared_ptr等智能指针。 Alternatively, ditch pointers and dynamic memory altogether, and just return your results by value from recurse() . 或者,完全沟通指针和动态内存,只需从recurse()返回值。

I don't see why you're allocating the memory on the heap to begin with: 我不明白为什么你要在堆上分配内存开头:

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;
}

By allocating only on the stack you're guaranteed that the variables will be cleaned up when the function returns. 通过仅在堆栈上分配,可以保证在函数返回时清除变量。

Otherwise I think you'd have to use some sort of smart pointer. 否则我认为你必须使用某种智能指针。

So I see three other problems in the code other than returning the address of a local variable that Adam Rosenfield pointed out. 所以除了返回Adam Rosenfield指出的局部变量的地址之外,我在代码中还看到了其他三个问题。

First, your resursive function will never end. 首先,你的恢复功能永远不会结束。 At some point in recurse(), you must check for a value that causes it to not call recurse() again and just return. 在recurse()的某个时刻,你必须检查一个值,使它不再调用recurse()并返回。 That is a fundamental part of recursion. 这是递归的基本部分。 The argument passed, v1, is also not being used. 传递的参数v1也没有被使用。

Second, the operator+() does not actually work. 其次,运算符+()实际上不起作用。 There is not a way to assign an int to a Number() object. 没有办法将int分配给Number()对象。

Third, in main you pass something called result which is never declared. 第三,在main中传递一个名为result的东西,它永远不会被声明。

Forgetting those errors, I assume that you want to allocate all the objects on the heap to avoid a stack overflow, where this function will recurse many times or the actual object used is much larger than Number. 忘记这些错误,我假设您要分配堆上的所有对象以避免堆栈溢出,此函数将多次递归或者使用的实际对象比Number大得多。 In that case by allocating the return variable on the heap inside recurse() you are forcing the caller to delete the returned object. 在这种情况下,通过在recurse()内的堆上分配返回变量,您强制调用者删除返回的对象。 So after the calls to recurse() in recurse() and main() you would have to delete the returned value. 因此,在recurse()和main()中调用recurse()之后,您必须删除返回的值。 The convention for indicating that to the caller is to return a pointer instead of a reference. 指示调用者的约定是返回指针而不是引用。 So recurse() and main() would look something like this: 所以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;
}

Note: Whatever recurse actually calculates is nonsensical. 注意:无论实际计算的是什么递归都是荒谬的。 I don't know what the intentions are but it is just something that works. 我不知道意图是什么,但它只是有用的东西。

Is there some reason you are dynamically allocating the memory? 您是否有动态分配内存的原因?

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

Also I notice you are not using the value v1 另外我注意到你没有使用值v1

But the big mistake is that the recursion has NO escape clause. 但最大的错误是递归没有逃避条款。
This is in effect an infinite recursion that will basically run out of memory. 这实际上是无限递归,基本上会耗尽内存。

Smart pointers are your friend. 聪明的指针是你的朋友。 Do a quick read-up on auto_ptr at the very least. 至少快速阅读auto_ptr。

Also, read Adam Rosenfield's comment on your other problem (returning a reference to a value that doesn't exist anymore). 另外,请阅读Adam Rosenfield对您的其他问题的评论(返回对不存在的值的引用)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM