首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

Effective C++中条款11的有关问题

2013-01-01 
Effective C++中条款11的问题条款11:在operator中处理自我赋值class Bitmap { ... }class Widget{...p

Effective C++中条款11的问题
条款11:在operator=中处理"自我赋值"


class Bitmap { ... };
class Widget{
   ...
private:
   Bitmap* pb;
};

下面是operator=的实现代码,表面看起来合理,但自我赋值出现时并不安全

Widget&
Widget::operator=(const Widget& rhs)
{
    delete pb;
    pb = new Bitmap(*rhs.pb);
    return *this;
}

这里的自我赋值问题是,operator=函数内的*this和rhs可能是同一个对象,如果这样的话,delete就不只是销毁当前对象的bitmap,它也销毁rhs的bitmap.
这句话我就没太明白,是不是operator=函数体内的this指针指向的是pb?如果这样的话,先是delete掉pb指向的内存空间,然后又new了一个新的对象,接着返回*this的话应该有值的,我这里不大懂,请讲解下.
接着,作者给出了解决方案:

Widget& Widget::operator=(const Widget& rhs)
{
    Bitmap* pOrig = pb;        //记住原先的pb
    pb = new Bitmap(*rhs.pb);  //令pb指向*pb的一个复件(副本)
    delete pOrig;              //删除原先的pb
    return *this;              
}

这段代码,我的理解就是:先是定义了一个指针pOrig指向pb原先所指的内存空间,然后使pb指向*rhs.pb的副本,接着删除pOrig,也就是删除老的pb所指的内存空间,最后函数返回*this,也就是*rhs.pb,这样,即使operator=函数内原先this和rhs指向同一个对象,删除时也不会出现问题,是这样吗?

[解决办法]
这个只是考虑delete和new的先后次序问题。

delete pb;     
pb = new Bitmap(*rhs.pb); 
这个先delete, 有可能rhs.pb就是delete掉的pb; 如果是这样,new就会出问题。


    Bitmap* pOrig = pb;        //记住原先的pb
    pb = new Bitmap(*rhs.pb);  //令pb指向*pb的一个复件(副本)
    delete pOrig;              //删除原先的pb
  这里先new,再delete就避免的上面的情况。
只是pd指向了新new的,所以原来的pb要先记下徕。
[解决办法]
他所考虑的是自身拷贝赋值的问题,比如:

Widget w;
w = w;

如果用上面第一个方式的话,就有问题了。因为它先销毁了自身,而此时右值也是自身,这就产生问题了。第二种方式则可以避免,因为它先建立一个新的拷贝,然后删除掉旧的。

还有一个解决方案就是通过一个指针判断:

Widget& Widget::operator=(const Widget& rhs)
{
if( this == &rhs )
  return *this;
//...as above
}

也可以解决这个问题。
[解决办法]

Widget&
Widget::operator=(const Widget& rhs)
{
    delete pb;
    pb = new Bitmap(*rhs.pb);
    return *this;
}
//若自我赋值的话,this指针指向rhs,则 delete pb释放掉了目的也就是源的数据,下面再new就没东西可new了(pb指向的东西已被释放)。所以他的解决办法就是先new完了,再释放

[解决办法]
这句话我就没太明白,是不是operator=函数体内的this指针指向的是pb?

不是这样的pb只是Widget中的一个成员,this是指向成员本身的,而不是指向他的成员,要访问成员可以用this来访问而已。delete pb;就是把pb指向的那部分空间删除或者说手动调用析构,这样的话如果是自我赋值,(*rhs.pb)这个pb指向的东西已经不在了,你对他进行取值操作就是很危险的事了.

热点排行