2010-03-03 37 views
1

我剛剛開始結合我對C++類和動態數組的知識。我被告知「任何時候我使用新的操作符」我應該刪除。我也知道析構函數是如何工作的,所以我覺得這個代碼是正確的:我在這裏使用的是否正確刪除?

的main.cpp

... 
int main() 
{ 
    PicLib *lib = new PicLib; 
    beginStorage(lib); 
    return 0; 
} 

void beginStorage(PicLib *lib) 
{ 
... 
    if (command != 'q') 
    { 
     //let's assume I add a whole bunch 
      //of stuff to PicLib and have some fun here 
     beginStorage(lib); 
    } 
    else 
    { 
     delete lib; 
     lib = NULL; 
     cout << "Ciao" << endl; 
    } 
} 

PicLib.cpp

... 

PicLib::PicLib() 
{ 
    database = new Pic[MAX_DATABASE]; 
    num_pics = 0; 
} 

PicLib::~PicLib() 
{ 
    delete[] database; 
    database = NULL; 
    num_pics = 0; 
} 
... 

我填補我PicLib與Pic類,包含更多動態數組。 Pic的析構函數以與上面相同的方式刪除它們。我認爲delete [] database正確擺脫所有這些類。

那麼刪除 main.cpp是必要的嗎?這裏一切都看起來很豪華嗎?

+0

爲什麼分別分配數據庫然後刪除它?如果它始終在課堂中,爲什麼不把它作爲成員Pic m_database [MAX_DATABASE]; – KPexEA 2010-03-03 18:07:49

回答

5

有幾個問題:

int main() 
{ 
    PicLib *lib = new PicLib; 
    beginStorage(lib); 
    return 0; 
} 

這是最好的分配和在同一範圍內刪除內存中,因此它很容易被發現。

但在這種情況下,剛剛宣佈在本地(通過引用傳遞):

int main() 
{ 
    PicLib lib; 
    beginStorage(lib); 
    return 0; 
} 

在beginStorage()

但我看不出有任何理由來操作的指針。通過引用傳遞它,並在本地使用它。

void beginStorage(PicLib& lib) 
{ 
.... 
} 

在PicLib類中,您有一個RAW指針:數據庫。

如果您有一個您擁有的RAW指針(您創建並銷燬它),那麼您必須覆蓋編譯器生成的版本構造函數和賦值運算符。但在這種情況下,我認爲沒有理由touse指針會更容易只使用一個向量:

class PivLib 
{ 
    private: 
     std::vector<Pic> databases; 
}; 
+0

啊,對第一個問題感到抱歉。我修改了代碼。簡化很難;) – Stephano 2010-03-03 17:07:47

+0

這就是我喜歡SO的原因;你們給我這麼多的東西來學習! :p – Stephano 2010-03-03 17:13:55

2

是的,除非你使用auto_ptr(並且在使用它之前閱讀auto_ptr的語義 - 你不能複製它)。

例如:

int main() 
{ 
    auto_ptr<PicLib> lib = new PicLib; 
    beginStorage(lib); 
    return 0; 
} // auto_ptr goes out of scope and cleans up for you 
0

一切看起來都不錯。

main.cpp中的刪除是必要的,因爲如果您沒有調用delete,那麼析構函數不會運行,您的數組也不會被刪除。你也會爲班級泄漏內存,而不是數組。

2

else不符合while。你想要更多的東西一樣:

void beginStorage(PicLib *lib) 
{ 
    while (command != 'q') 
    { 
     //let's assume I add a whole bunch 
      //of stuff to PicLib and have some fun here 
    } 

    delete lib; 
    lib = NULL; // Setting to NULL is not necessary in this case, 
       // you're changing a local variable that is about 
       // to go out of scope. 
    cout << "Ciao" << endl; 
} 

delete看起來不錯,但你應該確保記錄的是beginStorage採取PicLib對象的所有權。這樣,任何使用beginStorage的人都知道他們以後不必刪除它。

+0

ops,對不起。我添加了一個if。我簡化了代碼,顯然錯過了:)。乾杯。 – Stephano 2010-03-03 17:03:50

3

是的,任何你與必須被刪除刪除創建和任何與新的[]必須刪除創建刪除[],在一些點。

有一些事情我會在你的代碼指出,雖然:

  • 體型的std ::矢量<>在使用新的[]和delete []。它會爲你做內存管理。還可以看看像auto_ptr,shared_ptr這樣的智能指針,以及用於自動內存管理的C++ 0x unique_ptr。這些幫助您避免忘記刪除並導致內存泄漏。如果可以的話,根本不要使用new/new []/delete/delete []!
  • 如果你需要新增和刪除一些東西,這是一個非常好的主意新的類的構造函數,並刪除類的析構函數。當拋出異常時,對象超出範圍等,它們的析構函數會自動調用,所以這有助於防止內存泄漏。它被稱爲RAII。
  • beginStorage刪除它的參數可能是一個壞主意。如果您使用未使用新的創建的指針調用函數,它可能會崩潰,因爲您無法刪除任何指針。如果main()在堆棧上創建了PicLib而不是使用new和delete,並且beginStorage需要引用而不是刪除任何東西,那會更好。
+1

雖然有一個奇怪的現象:'typedef int a [1]; a * p = new a;刪除[] p;'。我會說「如果它是一個數組,使用delete []。如果不是,使用delete」。 – 2010-03-03 17:09:09

+0

哇,這是一個奇怪的邊緣情況。不知道! – AshleysBrain 2010-03-03 17:19:26

+0

這是一個奇怪的邊緣情況,但仍然使用新的[],只是「隱藏」在typedef中。 – 2010-03-03 17:32:30

1

一般而言,您想在新的地方刪除。它使會計更容易。更好的辦法是使用一個智能指針(在這種情況下是scoped_ptr),這意味着即使while的主體拋出異常並提前終止,您的代碼仍然正確。

2

的刪除main.cpp中是必要的。

這可能是個人喜好的問題,但我建議不要在單獨的邏輯部分中調用new和delete(這裏的PicLib實例的delete調用在單獨的函數中)。通常最好只對一個部分負責分配和取消分配。

@AshleysBrain有一個更好的建議(關於創建PicLib的堆棧),儘管如果PicLib佔用太多內存,這可能會導致問題。

0

是的,否則不會調用PicLib的析構函數。

儘管如此:如果您在函數中新建一個方法範圍對象,請嘗試在相同函數中將其刪除。作爲一名初級工程師,必須通過大型項目來修復其他人的內存泄漏......這使得其他人閱讀起來更容易。從它的外觀來看,您可以在beginStorage()返回後刪除* lib。然後在一個地方看到* lib的範圍會更容易。

相關問題