我有以下简单的矢量类,我可以定义不同大小的矢量并对它们求和;我重载了+运算符并包含一个简单的数据显示方法desplegar();该类定义为:
class Cvector{
private:
int dim;
float * C;
public:
Cvector(){};
Cvector(int n){dim=n; C = new float[dim];};
~Cvector(){delete [] C;};
int getdim(){return dim;};
float getC(int i){
if(i<dim && i>=0)
return C[i];
else
return 0;
};
void setC(int i, float x){
if(i<dim && i>=0)
C[i]=x;
}
void desplegar(){
cout<<"[ ";
for(int i=0;i<dim;i++)
cout<<getC(i)<<" ";
cout<<" ]"<<endl;
}
Cvector operator + (Cvector);
};
Cvector Cvector::operator + (Cvector A){
int n;
if(A.getdim()>dim)
n=A.getdim();
else
n=dim;
Cvector temp(n);
for(int i=0;i<n;i++)
temp.setC(i,getC(i)+A.getC(i));
return temp;
}
当我运行以下代码时,一切正常:
Cvector X(2);
Cvector Y(3);
定义维度2和3的对象
X.setC(0,1);
X.setC(1,4);
Y.setC(0,0);
Y.setC(1,6);
Y.setC(2,9);
为每个维度添加相应的值(X为2,Y为3)
X.desplegar();
Y.desplegar();
Cvector T=Y+X;
T.desplegar();
到此为止所有东西都正确显示,T显示向量Y和向量X的总和,这就是我想要的。但是当我跑步时
X.desplegar();
它只显示来自内存的不相关数据,似乎对象X在作为参数传递给operator +时被修改,为什么会这样呢?如果我改为使用指向对象的指针,则不会发生这种情况,但这似乎并不直观。
有人可以评论吗?
答案 0 :(得分:1)
问题出在您的operator+
。
Cvector Cvector::operator + (Cvector A)
在这里,您通过对其进行复制传递第二个操作数(在您的情况下为X
)。此副本(A
)会将C
指针指向与X
向量相同的内存:
Cvector T=Y+X;
在operator+
的末尾,副本将被销毁,析构函数将被调用,内存将被释放。由于此内存由X
和X
本身的副本共享,因此您将拥有垃圾。更改您的operator+
,以便参考,一切都会正常工作:
Cvector Cvector::operator + ( const Cvector & A )
请注意,实现复制构造函数也是一个好主意。
答案 1 :(得分:1)
当您使用参数pass-by-value重载operator +
时,将调用复制构造函数来实例化临时对象。默认情况下,复制构造函数是原始对象的按位副本。在方法返回之前,在temp对象上调用用户定义的析构函数,在该对象中释放底层存储。
要更正代码,请自行定义复制构造函数或通过引用传递参数。
请永远记住rule-of-three,即在您定义任何析构函数,复制构造函数和赋值运算符时,请考虑在这三者中定义其他函数。
答案 2 :(得分:0)
您错误地复制了矢量。 temp 在 operator + 的末尾自动调用析构函数,导致T有一个悬空指针。您可能正在做类似于X的事情,如果不查看完整的程序,很难说清楚。
答案 3 :(得分:0)
Cvector没有复制构造函数,因此将生成默认值:
Cvector::Cvector(Cvector const & original)
: dim(original.dim), C(original.C)
{}
这是一个浅副本,也就是说,你现在有两个具有相同C指针的对象。
因此,当您复制 X作为任何函数的参数时,会发生这种情况:
Cvector x;
// populate X
// now call this:
void foo(Cvector y) { // y is created as a copy of x
} // y is destroyed
当复制的参数被销毁时,它会删除与原始文件共享的C。
应该进行以下更改: