2009-06-14 68 views
15

在過去的幾天裏我很痛苦地學習了很多關於C++編程的知識。
我愛它:)
我知道我應該釋放內存 - 現在在我的世界中存在黃金「每個malloc = free」或「每個new = delete」規則,但是我將它們用於相當簡單的對象。
矢量呢?無論我在哪裏,我都在使用vector.clear(),但這顯然是不夠的,因爲我的內存泄漏很大。
你能指導我如何對待這件事?我應該刪除矢量<string>?

*編輯
謝謝,您的意見讓我想到了這個應用程序的運算,我將能夠完全消除該向量。 :O
對不起 - 我開始解釋我在這裏的用例,並且發現了我真正需要的東西。就像你每天爲18小時的最後3天編碼一樣:| *編輯2
這很瘋狂。通過代碼的小改動,我已經將內存使用量從2x130 mb(不斷增長)消除爲2x 13.5mb,不變的大小。感謝讓我以另一種方式思考這個問題。

Btw。這樣的自我代碼審查得到了一個名字 - 任何人都記得嗎當你問任何人(甚至你的母親或狗)並開始解釋你的問題時 - 突然間你自己解決這個5小時的問題,只是試圖從另一個角度來看問題,或者試圖總結一下它是什麼所有關於。我經常發現自己被捕獲...

+5

由於您是內存管理的新手,可能您可以解釋您是如何知道自己正在獲取內存泄漏。測量內存泄漏的一些方法並不能真正反映出發生了什麼。 – 2009-06-14 19:49:37

+0

你可能想發佈一些你如何使用矢量類的示例代碼。例如,你有指向動態創建對象的向量嗎? – 2009-06-14 19:57:03

+0

好吧,我只是看到,我的應用程序執行導致越來越多的內存佔用。我正在執行相當簡單的操作(在兩個進程中進行md5哈希,並與mpcih2綁定),對於我的測試,它完全是兩千五百萬次操作。一個進程發送給其他數據包(字符串),第二個爲其計算散列值。在執行結束時,我已經拍攝了兩次130 MB。這太正常了。 – IamDeveloper 2009-06-14 19:59:24

回答

19

規則是,當你清除對象的向量時,每個元素的析構函數將被調用。另一方面,如果你有一個指針向量,vector::clear()不會調用delete對他們,你必須自己刪除它們。因此,如果你所擁有的只是一個字符串向量,而不是指向字符串的指針,那麼你的內存泄漏必然是由其他東西引起的。

+0

這是否適用於一般?如果我有一個具有'std:vector'作爲它的一個屬性的類,當類被銷燬時,C++會調用這個析構函數嗎? – 2014-12-05 16:20:37

+4

是的。當一個對象被銷燬時,它的所有數據成員的析構函數被調用。但正如我所說,瞭解你在矢量中存儲的內容。如果它是一個對象的矢量,這些對象將與矢量一起被銷燬。如果它是一個指針向量,那麼你必須自己刪除它們。 – Dima 2014-12-05 16:24:39

7

調用v.clear()將銷燬v中當前保存的所有對象,但它不會釋放內存(假定該向量很快會被再次填充)。

如果你真的想釋放內存,這個成語是

vector<string>().swap(v); 

這將創建一個新的(臨時)載體,並與v交換其內容。臨時向量然後被銷燬,釋放內存。

+0

現在我看到了背後的意圖,但對我來說看起來很尷尬。它會和v.swap一樣嗎(向量())? – ypnos 2009-06-14 19:55:48

+2

看起來很尷尬,但它是減少'v.capacity()'的慣用方法。你的代碼片段不會編譯,因爲'vector ()'是一個右值,不能綁定到非const引用。 – avakar 2009-06-14 19:58:34

+0

澄清:在a .wap(b)中,a和b不相等。成員交換有一個參數,一個非const引用。你可以調用臨時對象的非const成員函數,所以在一個.wap(b)中,a可以是臨時的。但是b綁定到非const引用,不能是臨時的。 – MSalters 2009-06-15 07:49:57

4

的載體(如所有的標準容器)擁有它裏面的對象。
所以它負責銷燬它們。

注意:如果vector包含指針,則它擁有指針(而不是指針指向的指針)。所以這些需要刪除。但有更簡單的方法。

您可以使用智能指針向量。事實上,你應該使用幾乎所有形式的智能指針。如果你使用的是指針,你可能仍然像C程序員一樣編程。

所以:

std::vector<int> data; // clear is fine. 

std::vector<int*> data1; // Now things need to be deleted. 
// alternative 1: 
std::vector<boost::shared_ptr<int> > data2; // The shared pointer will auto 
              // delete the pointer. 
// alternative 2: 
boost::ptr_vector<int> data3;    // Here the container knows that 
              // it is holding pointers and will 
              // auto de-reference them when you 
              // its members. 

但它聽起來像你需要開始思考學習的智能指針。

int* x = new int(5); 
// Do stuff. 
*x = 8; 
delete x; 

// --- Instead use a smart pointer: 
std::auto_ptr<int> x(new int(5)); 
// Do stuff. 
*x = 8; 
// No delete (the auto ptr handles it. 
5

從STL容器刪除元素保證調用這些元素的析構函數。然而,如果你有一個pointer-to-T類型的容器,那麼你仍然必須自己釋放指向內存(在這種情況下,指針的「析構函數」被調用,這是一個無操作)。

如果您不想在此情況下手動管理內存,請考慮使用smart-pointer solutionpointer container

7

你不需要這樣做。 std :: string會自行清理,所以字符串不是你的問題。請記住,您沒有使用new,因此您不必使用delete

您應該瞭解RAII - 它使分配和釋放更簡單。您將以這種方式避免內存泄漏。

1

如果你有一個向量,它超出了範圍,向量中的所有對象都被銷燬。除非要轉儲內容並重新使用向量,否則不需要調用clear()。

但是,如果你有機會使用像vector這樣的東西,那麼被指向的對象的析構函數將不會被調用,因爲vector析構函數不會遵循由指針表示的indirections。

所有這一切,你真的確認你有真正的內存泄漏,並且它們是由向量中的數據引起的嗎?

0

正如rlbond建議的那樣,使用RAII。

絕對不要把新的和刪除的調用放到主代碼流中。總是嘗試將它們放入對象中,以便對象析構函數可以釋放需要釋放的內容。通過這種方式,您可以避免需要記住調用delete,它使您的代碼異常安全(假設您使對象的操作異常安全)。例如,如果您有一個指向STL字符串或C樣式字符數組的指針向量,請將其放入一個StringContainer(使用更好的名稱)並讓StringContainer存放一個向量,並在StringContainer析構函數中運行for循環刪除向量中的每個字符串。

您可以將StringContainer內部的矢量設置爲公共成員並直接使用它,但它甚至可以更好地設計爲使其成爲私有或受保護的,並添加一些成員函數來管理字符串* vector。

因此,您的主要C++程序不應該在任何地方看到新的或刪除。相反,它應該有很多堆棧分配對象,auto_ptrs和shared_ptrs。