2009-01-07 53 views
2

我在遞歸C++程序中分配和釋放內存時遇到問題。因此,如果不使用自動內存管理解決方案,我不知道是否有人可以幫我解決我遇到的內存泄漏問題。遞歸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); 
} 

,你可以看到在遞歸函數分配的內存泄漏,但我不確定在哪裏可以根據遞歸的性質釋放這些內存?

+0

「請糾正我犯任何錯誤或簡化」 - 你需要做的問題編輯爲我們做到這一點。 – 2009-01-07 22:23:12

回答

12

的問題是在這裏:

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

你返回引用一個局部變量(result),這是一大禁忌。局部變量分配在堆棧上,當函數退出時,變量消失。返回一個局部變量的引用是將一個指針返回到現在被用於其他事情的堆棧中,這會導致很多不好的結果。

您應該做的是按值返回(只需將返回類型從Number&更改爲Number)。確保你有一個合適的拷貝構造函數,或者編譯器自動生成的拷貝構造函數適合你的需要。這意味着當operator+返回時,它會生成副本(通常可以通過優化離開),並且由於不存在指針或引用,因此無法獲得損壞的返回值。

要修復內存泄漏,可以使用智能指針,如boost::shared_ptr。或者,也可以完全溝渠指針和動態內存,然後從recurse()返回值。

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

通過只對你保證這兩個變量將被清理的功能時,堆棧分配回報。我想你不得不使用某種智能指針。

0

智能指針是你的朋友。至少在auto_ptr上快速閱讀。

此外,閱讀亞當羅森菲爾德對你的其他問題的評論(返回一個不存在的值的引用)。

2

因此,除了返回Adam Rosenfield指出的局部變量的地址之外,我在代碼中發現了另外三個問題。

首先,您的resursive功能永遠不會結束。在recurse()的某個點上,你必須檢查一個值,它不會再次調用recurse()並返回。這是遞歸的一個基本部分。通過的參數v1也沒有被使用。

其次,運營商+()不實際工作。沒有辦法將int分配給Number()對象。

第三,在主要傳遞一些東西,從來沒有所謂的聲明的結果。

忘記那些錯誤,我假設你想在堆上分配的所有對象,以避免堆棧溢出功能,該功能會重複很多次或實際使用的對象比人數大得多。在這種情況下,通過在recurse()內部的heap上分配返回變量,你迫使調用者刪除返回的對象。因此,在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; 
} 

注意:無論實際計算的遞歸是無意義的。我不知道這些意圖是什麼,但它只是一些有用的東西。

+0

不是特例安全。如果你想這樣做,使用auto_ptr <>作爲partialResult – 2009-01-07 23:17:54

1

是有一些原因,你是動態分配內存?

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

此外,我注意到你沒有使用值V1

但最大的錯誤是,遞歸有 NO例外條款。
這實際上是無限遞歸將基本用完的存儲器。