2

当我执行 a = b 之类的操作时效果很好,但如果我执行 a = a,对于向量中的所有元素,我得到 -1.255 +-67。这是我的复制构造函数和赋值运算符:

VecXd(const VecXd &source){
    dimension = source.dimension;
    vector = new T[dimension];
    for(int i=0; i < dimension; i++)
        vector[i] = source.vector[i];
}

VecXd operator=(const VecXd &source){
    dimension = source.dimension;
vector = new T[dimension];
for(int i=0; i < dimension; i++)
    vector[i] = source.vector[i];
return *this;
}
4

5 回答 5

4

这是因为一旦分配新向量,您就会丢失 source.vector 的先前值。这是一个自赋值,所以 source 和 *this 指的是同一个对象,因此 vector 和 source.vector 是一回事。

您可以修复此问题以及内存泄漏,如下所示:

VecXd operator=(const VecXd &source){
    dimension = source.dimension;
    T *temp = new T[dimension]; // Don't loose source.vector yet
    for(int i=0; i < dimension; i++)
        temp[i] = source.vector[i];
    delete [] vector; // Delete old vector
    vector = temp;
    return *this;
}

更好的是,您可以防止自我分配以防止这种讽刺:

VecXd operator=(const VecXd &source){
    if(this == &source)
        return *this; // This is a self-assignment, so there's nothing to do
    delete [] vector; // Delete old vector
    dimension = source.dimension;
    vector = new T[dimension]; // Now we are sure that vector and source.vector differ
    for(int i=0; i < dimension; i++)
        vector[i] = source.vector[i];
    return *this;
}
于 2013-09-18T00:28:41.833 回答
3

如果两个向量相同,则此行将清除源向量的内容:

vector = new T[dimension];

所以复制循环发生的下一行,你正在将垃圾读入垃圾。对于真正安全的赋值运算符/复制构造函数,请使用复制交换模式

于 2013-09-18T00:21:15.490 回答
1

在定义自定义赋值运算符时,您始终必须处理“自赋值”情况。小样本:

Shape& Shape::operator=(const Shape& S) //Assignment operator overloading
{
    if(this==&source)       //Checking for self assignment.
    {       
        return *this;
    }
    m_id=S.m_id;
    return *this;
}
于 2013-09-18T00:32:47.407 回答
1

简短的回答:您正在覆盖vector指针,丢失数据(并泄漏内存)。

实现赋值运算符的最简单方法是复制和交换习语:

void swap(VecXd & other) {
    using std::swap;
    swap(dimension,other.dimension);
    swap(vector,other.vector);
}

VecXd& operator=(const VecXd &source){
    VecXd cpy (source);
    swap(cpy);
    return *this;
}

这是一个不错的选择,因为:

  • 自我分配自动工作
  • 无需额外delete
  • 如果你以后在你的类中添加其他成员,你只需要调整复制构造函数

如果交换操作符不抛出(应该如此),这保证了强大的异常安全性,即如果赋值操作符(通过复制构造函数)抛出,则对象的状态保持不变。

于 2013-09-18T01:03:34.857 回答
0
VecXd operator=(const VecXd &source){
    dimension = source.dimension;
vector = new T[dimension];
for(int i=0; i < dimension; i++)
    vector[i] = source.vector[i];
              ^
             here you assign uninitialized vector values
             to the same vector
return *this;
}

引用尚未构造或已销毁的对象的非静态成员是未定义的行为。此外返回参考而不是值:

VecXd& operator=(const VecXd &source){
   // ...
   return *this;
}

这将启用链分配a=b=c并检查自分配:

VecXd& operator=(const VecXd &source){
   if(this!=&source) {
       // ... do what needed
   }
   return *this;
}
于 2013-09-18T00:39:29.557 回答