2012-04-03 56 views
3

假設你有一個簡單的類是這樣的:這是否被認爲是內存泄漏?

class foo{ 
private: 
    int* mData; 
    int mSize; 
public: 
    foo(int size){ 
     mSize = size; 
     mData = new int [mSize]; 
    } 
    ~foo() { 
     mSize = 0; 
     delete [] mData; 
    } 
}; 

然後裏面主要你做:

int main() { 
    static int HUGE = 100000000; 
    foo a(HUGE); 
    // do something useful with a 
    // . 
    // . 
    // . 
    // Now I'm done with a; I do not need it anymore ... 
    foo b(HUGE); 
    // do something useful with b 
    // Ok we are done with b 
    return 0; 
} 

正如你看到的不再需要ab後,但由於它是在創建堆棧,析構函數將不會被調用,直到程序結束。現在,我知道這與new分配並忘記撥打delete不一樣,但這仍然在浪費記憶。你認爲這是「內存泄漏」還是隻是一個糟糕的編程?

另外,你會如何避免這種情況?

foo::~foo(){ 
    if (mData != NULL){ 
     delete [] mData; 
     mData = NULL; 
     mSize = 0; 
    } 
} 

另一種方式:一種方式是手動調用析構函數時,不再需要的對象,但是,除了面色難看又陌生!你,除非你改變析構像陷入的麻煩double free通過foo *pa = new foo (HUGE)在堆上創建a,然後在不再需要對象時調用delete pa。這有效,但有可能引入另一個可能的內存泄漏(如果忘記調用delete pa)。

有沒有更好的方法擺脫不需要的對象?

+1

我不認爲這是一個特別有建設性的問題。這一切都歸結於定義「內存泄漏」的含義。你清楚地知道發生了什麼,不管你稱之爲「內存泄漏」,「糟糕的編程」,還是其他什麼,都沒有太大的改變。噢,'std :: vector'確實能讓你的班級嘗試做什麼,但是做得對...... – 2012-04-03 16:54:41

+2

「手動調用析構函數」。即使使用您的解決方法,也會調用未定義的行爲。一定不要在同一個對象上調用析構函數兩次。 – 2012-04-03 16:56:02

+0

@Robᵩ請解釋爲什麼調用析構函數調用未定義的行爲? – GradGuy 2012-04-03 18:31:34

回答

10

當對象超出範圍時調用析構函數。 C++允許函數體內的任意範圍。寫下您的主要功能是這樣的:

int main() { 
    static int HUGE = 100000000; 

    { 
     foo a(HUGE); 
     // do something useful with a 
     // Now I'm done with a; I do not need it anymore ... 
    } 

    { 
     foo b(HUGE); 
     // do something useful with b 
     // Ok we are done with b 
    } 
    // etc. 
    return 0; 
} 

我看到你的例子是簡化,但在實際的程序,不要忘了無論是

  • 實施適當的拷貝構造函數和operator=foo
  • 爲私有拷貝構造函數添加聲明並operator=因此無法調用它。
+0

巴,你輸入比我快:) – 2012-04-03 16:56:52

+0

關於私人拷貝構造函數和'運營商='好的提示:) – GradGuy 2012-04-03 18:33:02

1

不,它的定義不是內存泄漏。

內存泄漏是在您分配內存並丟失句柄時出現的,因此您無法在之後釋放內存。只要你這樣做,無論你在哪裏或何時釋放記憶都沒有關係。

您可以添加一個封閉的範圍,迫使內存釋放:

{ 
    foo a(HUGE); 
} 
{ 
    foo b(HUGE); 
} 
+0

我不認爲內存泄漏是關於處理。這是關於減少可用內存。 – 2012-04-03 17:41:11

+0

@DennisCheung由於標準沒有提到內存泄漏或提供清晰的定義,維基百科將不得不這樣做 - http://en.wikipedia.org/wiki/Memory_leak – 2012-04-03 17:44:14

3

只要將你的大A和B的對象到自己的括號,如果你擔心範圍。

而這在技術上並不是內存泄漏,但它是非常糟糕的內存管理,如你所說。


{ 
    { 
    foo a(HUGE); 
    } 
    ... 

    { 
    foo b(HUGE); 
    } 
1

這不是一個內存泄漏,因爲你做你分配的內存的不鬆動軌道。然而,這是無效的,特別是當程序運行時間更長時,應該避免。

使用範圍可縮短一個對象的生命週期:

int main() { 
    static int HUGE = 100000000; 
    { 
     foo a(HUGE); 
     // do something useful with a 
     // . 
     // . 
     // . 
     // Now I'm done with a; I do not need it anymore ... 
    } 
    { 
     foo b(HUGE); 
     // do something useful with b 
     // Ok we are done with b 
    } 
    return 0; 
} 

此外,值得重新考慮,如果這個代碼兩個部分應該是獨立的功能,那麼分配的對象將返回時釋放從功能。

0

你認爲這是「內存泄漏」還是隻是一個糟糕的編程?

不,它不是內存泄漏。

你會如何避免這種情況?

寫小函數,幾行。您的代碼將更具可讀性,堆棧中分配的未使用變量將被釋放。

0

這不是內存泄漏;然而恰恰是Firefox開發者花費了很長時間修復的那種內存使用情況。

範圍可能是解決這個問題的最簡單方法,如Dark Falcon所示。或者將分配和相關的代碼移到不同的功能中。

還可以使用std::auto_ptr更安全地處理指針,以便在發佈範圍時釋放指針。

0

你是否認爲這是「內存泄漏」

不,除非你做這樣的事情在中間的longjmp。

或只是一個糟糕的編程?

我認爲使用新的[]在你的類不良編程實踐中分配數組,因爲你有std :: vector。

另外,你會如何避免這種情況?

圍富成範圍:

{ 
    foo a(HUGE); 
} 

除非你改變析構函數是這樣的:

刪除忽略空指針。析構函數只被調用一次,所以不需要零變量。手動調用析構函數是一個VERY BAD IDEA - 它不是那個意思。如果你想重新初始化結構,實現clear()或resize()方法。

有沒有更好的方法來擺脫不需要的對象?

是的,將它們放在範圍內。

1

該類的構造函數還可以將您在'main()'函數中分配的內存塊作爲參數。這樣,一旦使用內存塊完成'a',您也可以將它傳遞給'b'。 'foo'析構函數根本不需要釋放任何內存,也不需要擔心會浪費內存,或者根本不用擔心對象的生命週期。

0

這不是一個內存泄漏,但如果你有一個變量,你需要一個函數的前半部分而不是第二個函數,這個函數很可能會做很多事情,並且應該被重構成兩個(或更多)分開的功能。

0

提取縮小範圍的函數。給他們好名字:

void do_a(int amount) 
{ 
    foo a(amount); 
    // ask `a` to be useful 
} 

void do_b(int amount) 
{ 
    foo b(amount); 
    // ask `b` to be useful 
} 

int main() { 
    static int HUGE = 100000000; 

    do_a(HUGE); 
    do_b(HUGE); 

    return 0; 
}