2016-11-29 119 views
1

這裏的數組是代碼:刪除對象

class A { 
    private: 
     int *anArr; 
     int id; 
    public: 
     A() { 
      id = 0; 
      anArr = new int[10]; 
     } 
     A(int i) { 
      id = i; 
      anArr = new int[10]; 
     } 
     ~A() { 
      delete[] anArr; 
      std::cout << "Class A id : " << id << " destructor" << std::endl; 
     } 
    }; 

    class B { 
    private: 
     A *anArr; 
    public: 
     B() { 
      anArr = new A[10]; 
     } 
     ~B() { 
      std::cout << "Class B destructor" << std::endl; 
      delete[] anArr; 
     } 
     void changeAnElement() { 
      anArr[2] = A(1); 
      anArr[2] = A(2); 
     } 
    }; 

    int main() 
    { 
     B b; 
     b.changeAnElement(); 

     return 0; 
    } 

輸出:

Class A id : 1 destructor 
Class A id : 2 destructor 
Class B destructor 
Class A id : 0 destructor 
Class A id : 0 destructor 
Class A id : 0 destructor 
Class A id : 0 destructor 
Class A id : 0 destructor 
Class A id : 0 destructor 
Class A id : 0 destructor 
// Gives heap error here 

所以,如果我沒有錯,當我改變對象數組的元素就不會調用析構函數。 我的第一個問題是在更改後的索引處發生的舊對象發生了什麼?它中的數組是否泄漏?我認爲我需要自己調用析構函數來防止內存泄漏,但它會產生堆錯誤。 第二個問題是我得到堆錯誤(Expression: _CrtlsValidHeapPointer(block))呼籲改變的對象的析構函數時。我不知道爲什麼,它適用於在構造函數中創建的。 謝謝!

+1

請注意,如果你是在類的手工做內存管理,你需要遵循的3或5 – NathanOliver

+1

我想象的規則,'anArr [0] = A(1)'等同於'anArr [0] .operator =(A(1))',它將構建一個新的'id'爲'1',用'A,id = 1'調用'anArr [0]'的拷貝構造函數,然後破壞'A,id = 1'。 A :: operator ='的默認實現不會爲你管理你的內存,所以你會泄漏。解決方案:實現複製構造函數或使用'std :: vector' /'std :: array' – lcs

+0

@NathanOliver謝謝,我從未聽說過它們。 –

回答

2

我的第一個問題是在更改後的索引處發生了什麼舊對象?

數組中的對象永遠不會去任何地方。 「舊」對象保留在該索引中。您調用該對象上的賦值運算符。賦值運算符修改對象。

其中的數組是否泄漏?

對象在賦值之前指向的數組確實泄漏,是的。

我想,我需要調用析構函數自己,以防止內存泄露

您與new[]創建的對象,這樣你就需要調用delete[],這的確調用析構函數。

,但它給堆錯誤

那是因爲你沒有按照rule of 3 (or of 5)

anArr[2]包含臨時A(2)含有相同的指針,但由於臨時的析構函數已經運行時,它已經刪除陣列和anArr[2]析構函數,然後嘗試再次刪除。這是不能做的事情之一。


結論:

  • 當你做手工的內存管理,遵循3
  • 規則不要做手工的內存管理。取而代之,使用std::vectorstd::array
1

更改後的索引處的舊對象會發生什麼變化?

它被重新分配。在C++中,這條線

anArr[2] = A(1); 

使得一個新的臨時對象A(1),將該值分配到現有的對象anArr[2],並破壞臨時對象。 anArr[2]始終是相同的對象,只有其值發生變化。由於它不是新創建的,所以在這一點上它也不會被破壞。但是請注意,臨時對象被銷燬了,並且刪除了那個int[10],即anArr[2]認爲(錯誤地)它擁有。

當該值是一個指向需要釋放的現有資源的指針時,您需要編寫一個用戶定義的賦值運算符A::operator=(const A&)。 「三規則」說,大多數情況下,您需要一個自定義析構函數,自定義複製構造函數或自定義複製賦值運算符,您還需要其他兩個。 (自C++ 11以來,移動構造函數和移動賦值被添加到該列表中,從而制定了「五項規則」)。