为什么我的赋值运算符不能用于自我赋值?

时间:2013-09-18 00:16:13

标签: c++ operator-overloading assignment-operator

当我执行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;
}

5 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:3)

如果两个向量相同,则该行消除源向量的内容:

vector = new T[dimension];

因此,复制循环发生的下一行,您正在将垃圾读入垃圾箱。对于真正安全的赋值运算符/复制构造函数,请使用copy-swap pattern

答案 2 :(得分: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;
}

答案 3 :(得分: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
  • 如果您稍后将其他成员添加到您的班级,则只需调整复制构造函数

Bonus 如果交换运算符没有抛出(应该如此),这可以保证强大的异常安全性,即如果赋值运算符抛出(通过复制构造函数),则对象的状态保持不变

答案 4 :(得分: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;
}