以下是代码:
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)
)。我不知道为什么,它适用于在构造函数中创建的那些。
谢谢!
答案 0 :(得分:2)
我的第一个问题是在更改的索引处旧对象会发生什么?
数组中的对象永远不会出现在任何地方。 &#34; old&#34;对象仍然在该索引中。您在该对象上调用赋值运算符。赋值运算符修改对象。
它中的数组是否泄漏?
对象在赋值之前指向的数组确实泄漏了,是的。
我认为我需要自己调用析构函数来防止内存泄漏
您使用new[]
创建了对象,因此您需要调用delete[]
,它确实会调用析构函数。
但它给出了堆错误
那是因为你忘了关注rule of 3 (or of 5)。
anArr[2]
包含与临时A(2)
包含的指针相同的指针,但由于临时的析构函数已经运行,它已经删除了数组,然后anArr[2]
的析构函数尝试再次删除它。这是必须要做的事情之一。
结论:
std::vector
或std::array
。答案 1 :(得分:1)
更改索引时旧对象会发生什么?
重新分配。在C ++中,这一行
anArr[2] = A(1);
创建一个新的临时对象A(1)
,将该值分配给现有对象anArr[2]
,并销毁临时对象。 anArr[2]
始终是同一个对象,只有它的值会发生变化。由于它不是新创建的,因此此时也不会被销毁。但请注意,临时对象已被销毁,并删除了int[10]
认为(错误地)拥有的全新anArr[2]
。
当值是指向需要释放的现有资源的指针时,您需要编写用户定义的赋值运算符A::operator=(const A&)
。 &#34;三法则&#34;说大多数需要自定义析构函数,自定义复制构造函数或自定义复制赋值运算符的情况,您还需要其他两个。 (从C ++ 11开始,移动构造函数和移动赋值被添加到该列表中,制作&#34;规则为五&#34;)。