对象Second
什么时候超出范围?如果我留下第三个cout语句,我会得到编译器错误。即使我围绕Second
和cout语句的初始化。
#include <iostream>
using namespace std;
class MyArray{
public:
int Size;
int* data;
MyArray(int s) : Size(s), data(new int[s]){}
~MyArray(){
delete[](this->data);
}
};
int main()
{
MyArray First(20);
First.data[0] = 25;
MyArray Second = First;
cout << First.data[0] << endl;
cout << Second.data[0] << endl;
cout << Second.data[0] << endl;
system("PAUSE");
return 0;
}
运行时错误:
答案 0 :(得分:3)
以下是正在发生的事情:MyArray
对象在初始化时获得一个指向它们自己的整数数组的指针,称为data
。但是,此行会更改Second
对象的内容:
MyArray Second = First;
现在,First.data
和Second.data
都指向相同的int[]
数组,因为默认的复制构造函数和赋值运算符执行浅副本。
这很糟糕,因为编译器可以自由地在代码中最后一次使用后销毁First
。因此,访问Second.data[0]
可能已无效。
此外,一旦First
和Second
超出main()
末尾的范围,他们 将尝试删除data
。只有第一个会成功;第二个将触发未定义的行为。
为避免将来出现此类错误,请使用rule of three。它说如果你定义了析构函数,复制构造函数或赋值运算符,你可能需要它们全部三个。
您的代码只有析构函数。添加复制构造函数和赋值运算符将解决此问题,并防止在分配MyArray
对象时出现内存泄漏。
答案 1 :(得分:1)
两个名称的范围都以}
结尾。 (范围是编译时的概念。)
Second
的生命周期在执行到达块结束时结束,之后First
的生命周期结束。但是你的程序有未定义的行为,因为你删除了两次数组,所以任何事情都可能发生。
答案 2 :(得分:1)
您需要使用复制构造函数
执行深层复制MyArray(const MyArray &t)
{
t.size = size;
if(size not_eq 0)
{
t.data = new int(size);
for(int i=0 ; i<size ; i++)
t.data[i] = data[i];
}
}
在此MyArray Second = First;
之后将正常工作 如果你想分配那么你也必须写作赋值运算符