我的编程背景是Java世界,但我刚开始学习C ++。我偶然发现了这个相当微不足道的,可能是相当愚蠢的问题,这个问题在某种程度上困扰着我作为Java程序员:
我有一个带有数组的类,该数组在构造函数中通过new初始化并在析构函数中删除。现在当我创建这个类的对象并将该类的另一个对象分配给同一个变量时(至少我认为是这样),析构函数中的delete []方法似乎在变量离开时被调用两次scope(在本例中为main()函数)(调试器给我一个_BLOCK_TYPE_IS_VALID断言失败警告)。
为什么?在为f分配新对象之前,为什么没有调用解构器?我怎么能明确地删除Foo(1)?这到底发生了什么?
class Foo{
private:
int *field;
public:
Foo(int size){
field = new int[size];
}
~Foo(){
delete[] field;
}
};
int main(){
Foo f = Foo(1);
f = Foo(2);
}
答案 0 :(得分:5)
C ++世界中有一些名为Rule Of Three的东西。
课程会自动为您生成析构函数,复制构造函数和赋值运算符。
如果您必须手动定义其中一个功能,您可能需要定义所有这三个功能。
在您的情况下,您应该定义两个复制功能,以便Foo
的副本获得自己的field
副本。添加这两个功能:
class Foo{
Foo( const Foo &f ) {
size = f.size;
field = new int[size];
std::copy( f.field, f.field + size, field );
}
Foo& operator=( const Foo &f ) {
// Leverage the logic that was already written in the copy constructor
Foo tmp(f);
std::swap( *this, temp );
return *this;
}
};
请注意,我假设您已将size
存储在Foo
对象中。您可能需要将这些信息存储在实际应用程序中
答案 1 :(得分:2)
你没有遵守三条规则,这是不好的。由于默认的复制构造函数执行浅复制,因此所有自动变量(f
和临时值)都使field
成员指向同一个int
,当析构函数被多次销毁时被称为。
实现适当的复制构造函数,或使用C ++习语并完全避免手动管理 - 即改为使用std::vector
。