条款11:在operator=处理自我赋值

自我赋值发生在对象被赋值给自己:

class Widget {

...

}

Widget w ;

w = w // 赋值给自己

还有一个隐含的会发生自我赋值的例子:

         a[i]  = a[j];//当i = j时

下面有这样一个类:

class Bitmap{};

class Widget {

       ...

private :

       Bitmap *pb;

};

l  版本一

Widget& Widget::operator= (const Widget& rhs){

              delete pb;

              pb = new Bitmap(*rhs.pb);

              return *this;

}

注意:这里存在一个问题,那就是如果rhs所指的对象就是this。Delete pb后,就把this的pb删除了,所以不行。

 

欲阻止这样的错误,可以加上一个证同测试:

l  版本二

Widget& Widget::operator= (const Widget& rhs){

              if(this == rhs) return *this; // 证同测试

              delete pb;

              pb  = new Bitmap(*rhs.pb);

              return *this;

}

 

这样做法是可以的,但是还有一个问题是如果在new Bitmap时,出现的异常,则会使widget对象最终会持有一个指针指向一块被删除的bitmap。这样的指针是有害的,你无法安全的删除它们,也无法安全的读取它们。

 

但是精心安排一下,是可以避免这个错误的:

l  版本三:

Widget& Widget::operator= (const Widget& rhs){

              Bitmap *obj = rhs.pb;

              pb  = new Bitmap(*rhs.pb);

              delete obj;

              return *this;

}

现在如果new Bitmap出现的异常,pb也会保持原状。注意,虽然我们没有加入证同测试,但是上面的代码也可以处理自我赋值现象。

 

版本四:

针对版本三还有一个替换版本:

class Widget {

public:

    ...

    swap(Widget& rhs);

private :

    Bitmap *pb;

};

Widget& Widget::operator= (const Widget& rhs){

           Widget temp(rhs);

           swap(temp);

           return *this;

}

这项技术被称为copy and swap技术。

  • 请记住:
  • 确保当对象自我赋值时operator=有良好的行为。其中的技术包括
  1. 比较“来源对象”与“目标对象”的地址
  2. 精心周到的语句顺序
  3. Copy and swap技术
  • 确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为也是正确的
posted @ 2012-11-15 22:31  loveyakamoz  阅读(226)  评论(0编辑  收藏  举报