2012-02-17 60 views
2

我有一個小型的C++程序,我創建了一個Person類的兩個對象。該課程有char *m_szFirstNamechar *m_szLastName數據。當它被刪除之前刪除內存

然後我分配一個對象到另一個對象,導致對象的數據成員指向相同的位置。
在析構函數中,我刪除了爲第一個對象分配的內存並將NULL值分配給指針。像這樣的東西。

if (m_szFirstName!= NULL) 
{ 
    delete [] m_szFirstName; 
    m_szFirstName = NULL; 
} 

然後,當我去刪除第二個對象的內存,爲NULL檢查不工作,當我刪除的記憶,我得到一個崩潰。從調試器,它顯示我的指針不是NULL。它有0xfeee

我知道內存已被刪除,不應刪除。但是,我不知道如何檢查是否應該刪除內存。

+0

你能展示一些代碼嗎? – cnicutar 2012-02-17 07:15:38

+0

當你複製你的Person實例時,第二個對象擁有**自己的**成員。也就是說,它有自己的'm_szFirstName',它的值是從原始實例複製的。請注意,只有指針被複制,而不是指向的內存**。所以當你在刪除第一個實例後將第一個實例設置爲NULL時,第二個實例將保留它的值並指向「已刪除」的內存。 – ereOn 2012-02-17 07:34:32

+0

代碼太大,無法在此處添加。我想示範你不能將一個對象(用char *數據)分配給另一個對象,除非你拒絕賦值操作符並在其中做一個拷貝。否則,兩個對象的數據將指向相同的內存。當第一個對象被刪除時,第二個對象數據將有損壞的數據。 – 2012-02-19 18:10:24

回答

4

原因崩潰:
您應該遵循Rule of Three避免懸擺指針的這個問題。

如果您需要自己顯式聲明析構函數,複製構造函數或複製賦值運算符,則可能需要明確聲明它們中的所有三個。

您的情況您沒有定義複製賦值操作符,從而導致指針的淺拷貝。

建議解決方案:

如果您可以使用的std::string代替char *只是簡單地使用std::string,它比任何一種愚蠢的指針的東西首先是偏好。
您可以使用std::string來避免所有時髦的指針。

如果您無法閱讀,以下建議適用於任何類別指針成員。

請注意,這裏的理想解決方案是根本不使用原始指針,每當您使用原始指針時,您都不得不手動管理它們獲取的資源,但手動管理資源總是困難且容易出錯。責任是爲了避免它。

要做到這一點,你應該使用Smart pointer將管理指針implicitly.Using智能指針的動態內存將確保動態內存使用情況&後含蓄地釋放您不必手動管理它。

你的情況是這個原因,在C++中,你應該依靠RAII而非人工資源管理&使用的是智能指針去了解你的情況的方式。

警告:
注意,我剋制住自己從提示其中智能指針使用的,因爲選擇,而依賴於所有權一生所涉及的元素,這是不是從數據清楚在Question.So我會建議閱讀提供,

Which kind of pointer do I use when?

,使您的智能指針的選擇使用。

+0

注意:使用RAII時,您應該遵循[二大法則] http://www.artima.com/cppsource/bigtwo.html – Arafangion 2012-02-17 07:32:18

+0

好的答案。然而,在他的情況下,很可能他真正需要的是一個「std :: string」來存儲它的名字和姓氏。 – ereOn 2012-02-17 07:37:06

+0

@ereOn:*可能*是,*當然*我們不知道,不管怎樣,對於任何指針成員來說,答案總的來說都很好。當然,如果一個人可以使用'std :: string',它首先會優先於任何一種愚蠢的指針。我看到很多Assignments相關的Q的推動解決方案不使用'std :: string'這是很愚蠢的,我假設這些情況之一。反正我會編輯答案來反映這一點。謝謝。 – 2012-02-17 07:39:15

0

不要再刪除它,如果(m_szFirstName == m_szLastName)。 但是,這會給你一個內存泄漏(當你分配一個指針到其他)。

1

隨着

if (m_szFirstName!= NULL) 
{ 
    delete [] m_szFirstName; 
    m_szFirstName = NULL; 
} 

你只設置m_szFirstName指向NULL,不m_szLastName。這意味着你必須有一些方法來跟蹤他們指向同一位置的事實。他們指向同一地點是否有理由?你可以複製這個名字,而不是將指針指向同一個地方嗎?

如果你需要兩個指針共享相同的數據,我會看看std :: tr1 :: shared_ptr,它將通過跟蹤引用的數量和刪除數字來解決這個問題引用達到0.

0

當您有兩個指向同一位置的指針(在您將第一個指向第二個指針後)時,您有兩個指針指向相同的地址。刪除一個可以釋放它們兩個指向的內存。但設置一個到NULL不會改變另一個指針。例如,如果您有兩個整數,則會發生同樣的情況。

int a = 3; 
int b = a; 

現在,如果你運行

a = 0; 

b值不會改變。第二個指針在改變第一個指針時不會改變(但是當您更改指針指向的內存時,您也可以通過另一個指針查看效果)。

0

您的問題是一個經典的C/C++問題,稱爲「懸掛指針」問題。解引用懸掛指針導致崩潰。問題在於引用計數。一旦將相同的內存分配給第二個指針,那麼引用計數應該是2.因此,如果刪除一個指針,引用計數應該變爲1,並且除非count爲0,否則不應該釋放或釋放內存。在0時,它可以被垃圾收集。

現在有很好的答案可以解決你的問題。由於您使用的是C++,因此您可以使用類似於auto_ptr(OR shared_ptr)的內容。他們提供了我上面提到的,引用計數的東西,甚至你不必擔心刪除或釋放你的對象,這些類會照顧。他們在稱爲RAII模式的simething上工作,當堆棧中的對象超出範圍時,會自動調用析構函數。

0

只要在刪除對象時將指針設置爲NULL即可。正如你所看到的,它只會導致疼痛。你不能假設,因爲指針不是NULL,它還沒有被刪除。

您可以使用任何明智的模式來避免此問題。例如,Boost的shared_ptr是一個不錯的選擇。

+0

將指針設置爲nullptr或NULL是刪除操作後應該做的事情,這樣如果再次刪除相同的指針,則不會發生任何情況。就我而言,由於一些愚蠢的原因,它崩潰了。無論如何謝謝你的建議。 – 2012-02-23 22:44:32

+0

@SaleemYusuf如你所見,如果你再次刪除同一個指針,它不會阻止你導致崩潰。它所做的只是讓你認爲如果一個指針變量保存一個非NULL的值,這意味着訪問是安全的,這是**不是** true。所以這是一個非常不好的習慣。而不是將指針設置爲NULL,只是不要訪問它。 (或者,更好的是,使用一個合理的指針類。) – 2012-02-23 22:48:02