2016-11-29 120 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以来,移动构造函数和移动赋值被添加到该列表中,从而制定了“五项规则”)。