2014-05-09 109 views
1

在C++中,調用new的指針是否包含new'd數據刪除舊數據?C + +構造函數/析構函數調用&動態創建的數據調用「新」刪除舊數據?

我想說它沒有,而且會導致泄漏。在已經包含數據的指針上調用new肯定會將指針指向新數據,並且我們將失去對舊數據的引用?

我問,因爲我是看着this page,我注意到在車隊已經提出,OP做到這一點:

MyString::MyString() 
{ 
    // A new, empty string contains zero characters plus a terminating zero. 
    nlength = 1; 
    nstring = new char[1]; 
    nstring[0] = '\0'; 
} 

MyString::MyString(const char *input) 
{ 
    // A new, copy of a C-string contains exactly the same number of characters in 
    // the C-string plus a terminating zero. 
    nlength = strlen(input) + 1; 
    nstring = new char[ nlength ]; 
    strcpy(nstring, input); 
} 

MyString::MyString(const MyString& S) 
{ 
    nlength = S.nlength; // we know this is correct! 
    nstring = new char[ nlength ]; 
    strcpy(nstring, S.nstring); 
} 

//nstring is deleted in the destructor 
MyString::~MyString() 
{ 
    delete[] nstring; 
} 

這似乎很奇怪,我。因爲,如果nstring已經被定義,那麼它會泄漏?沒有?

但是,這些都是構造函數,所以我猜這裏的邏輯是它們只會在每個實例中調用一次。這就說得通了。然而,會發生什麼,如果我做了以下內容:

MyString myString("test"); 
myString = MyString("test2"); //is the destructor invoked here? 

如果析構函數被重新分配時調用的myString然後這一切對我來說很有意義。

因此,在總結,兩件事情我想證實:

  • 如果分配new數據已經有new數據的指針,那麼這會泄漏,是否正確?
  • 重新分配對象時,對象的析構函數是否被調用?
+2

1)正確。它會泄漏。 2)在上面的例子中,你問的是被調用的析構函數,答案是肯定的。但你真的應該自己測試一下。創建一個簡單的控制檯應用程序非常簡單,在構造函數/析構函數中使用cout/printf,並使用賦值和複製構造函數來查看實際的功能。 – zumalifeguard

+0

@zumalifeguard ack,我一直在測試各種各樣的東西,出於某種原因,我沒有想到要真正測試析構函數。我現在會這樣做。謝謝你指出。 – Jace

+0

我認爲對「這裏調用的析構函數」的洞察力是「是的 - 但可能不是你想的那個」等號的析構函數右側的MyString運行。等號左側的myString調用其賦值運算符。 –

回答

2

你對指針行爲是正確的:當指針被重新分配時,內存不會被釋放。

與您的代碼的問題(我改了名字的變量,以避免混淆):

MyString x("test"); 
x = MyString("test2"); 

是第二行不會再次調用x構造函數和析構函數。在C++中,每個對象只調用一次構造函數和析構函數。此代碼調用轉讓運營商

順序調用是:

  1. 呼叫的x"test"構造。
  2. 使用"test2"調用未命名的臨時構造函數。
  3. 用臨時對象調用x的賦值運算符。
  4. 調用臨時對象的析構函數。
  5. 在當前作用域的末尾,調用x的析構函數。

賦值操作符應該定義或多或少是這樣的:

const MyString &MyString::operator=(const MyString&o) 
{ 
    nlength = S.nlength; // we know this is correct! 
    delete []nstring; 
    nstring = new char[ nlength ]; 
    strcpy(nstring, S.nstring); 
    return *this; 
} 

當然,這代碼不是異常安全的。如果這個new失敗會發生什麼?該對象將被打破!因此,請改爲:

const MyString &MyString::operator=(MyString o) 
{ 
    swap(*this, o); 
    return *this; 
} 

這被稱爲copy-n-swap idiom,或類似的東西。在運行點3時,本operator=調用序列上面會:

  1. 呼叫的o拷貝構造函數傳入暫時的。
  2. 交換othis的值。
  3. 調用o的析構函數,將刪除第一個分配("test1")。
+0

很好的答案。並感謝您提供有關「複製 - 交換(或類似的東西:P)」成語的更多信息。 – Jace

2

否,任何指針通過調用返回到newnew[]或必須使用到deletedelete[]相應的呼叫被free'd。

int* x = new int; 
x = new int; // Memory leak! 

在C++ new是一個運算符,它返回堆中分配的對象。它並不關心你分配給它。唯一重要的是,通過new返回的對象最終傳遞給delete運營商。

1

構造函數在任何其他成員函數之前被調用。因此nstring已經不可能指向一些分配的內存。

如您所說,x = new int;不是delete無論x指向之前(如果有的話)。

該行:myString = MyString("test2");來電myString.operator=(MyString("test2"));。你說話就好像你認爲它被破壞了MyString然後構建了一個新的,但是這沒有發生。它只是一個我們稱之爲複製賦值操作符的函數,您應該實現這個函數。

表達式MyString("test2")中涉及到構造和破壞,但不影響myString

1

In C++, does calling new on a pointer that holds new'd data delete the old data?

號必須delete分配的內存。

If the destructor is invoked upon reassigning myString then it all makes sense to me.

MyString myString("test"); 
myString = MyString("test2"); //is the destructor invoked here? 

您發佈的代碼是有趣的。除了施工之外,還有一項任務已經完成。你的班級的問題是它缺少一個用戶定義的賦值操作符(至少它沒有顯示),所以內存泄漏。

0

new不釋放預先分配的內存。如果在取消分配資源之前使用new,您將獲取內存泄漏。在你的例子中,做myString = MyString("test2")的確會導致內存泄漏,因爲複製賦值操作符(或者取決於編譯器版本的移動分配)沒有花時間來清理已由nstring保存的內存。這兩個函數都是由編譯器提供的,因爲您自己並沒有創建它們,並且它們的工作(默認情況下)僅僅是複製(或移動)成員方式,而不考慮內存管理。