在C ++中作为参数传递给函数时修改的对象

时间:2013-11-26 07:50:04

标签: c++ object pointers vector arguments

我有以下简单的矢量类,我可以定义不同大小的矢量并对它们求和;我重载了+运算符并包含一个简单的数据显示方法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 +时被修改,为什么会这样呢?如果我改为使用指向对象的指针,则不会发生这种情况,但这似乎并不直观。

有人可以评论吗?

4 个答案:

答案 0 :(得分:1)

问题出在您的operator+

Cvector Cvector::operator + (Cvector A)

在这里,您通过对其进行复制传递第二个操作数(在您的情况下为X)。此副本(A)会将C指针指向与X向量相同的内存:

Cvector T=Y+X;

operator+的末尾,副本将被销毁,析构函数将被调用,内存将被释放。由于此内存由XX本身的副本共享,因此您将拥有垃圾。更改您的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。


应该进行以下更改:

  1. 正确编写一个复制构造函数和赋值运算符,执行深层复制(这将阻止副本在销毁时破坏原始对象)
  2. 当您不更改时,通过const引用传递参数