从operator=中“自我赋值”看new的抛出异常

来源:互联网 发布:情趣睡衣淘宝买家秀 编辑:程序博客网 时间:2024/06/18 04:00

在Effective C++中看到这个问题时才发现以前写的代码完全没有注意过这个问题

“自我赋值”发生在对象被赋值给对象本身时,例如:

class Weight{...};...w=w;

虽然这看上去确实非常的蠢,但是谁也不能保证这不会发生,毕竟这是合法的,但是问题出来了,我们写的显示赋值函数一般是这样的,假设我们在类中使用了动态分配。

class Bitmap{...};class Weight{...private:Bitmap * _pb;};Weight & Weight::operatot=(const Weight & rhs){delete _pb;_pb=new Bitmap(rhs._pb);return *this;}

好的,现在面临的问题是,*this和rhs这两个指向了同一个对象,在执行delete _pb 时同时也将rhs的Bitmap销毁了。

对此提出了两种有效的解决方法

①传统做法在operator=之前做一个“证同测试(identity test)”

Weight & Weight::operatot=(const Weight & rhs){if(this == &rhs)    return *this;delete _pb;_pb=new Bitmap(rhs._pb);return *this;}

这样做完全行得通,但是为一件很少发生的事情花费额外的判断操作似乎不是很划算。

②依靠精心周到的语句顺序解决
调整最初的源代码

Weight & Weight::operatot=(const Weight & rhs){Bitmap *pOrig=_pb;                    //记住原先的_pb_pb=new Bitmap(rhs._pb);              //令_pb指向*_pb的一个副本delete pOrig;                         //删除原先的_pbreturn *this;}

再调整顺序后,在重新new之后再摧毁原来的_pb,这样的操作具有很高的异常安全性。这里有一个问题,如果new失败了怎么办?

我相信所有人一定都写过这样一段代码

int *p=new int[5];if(p==NULL)    return -1;

当我们使用malloc/calloc分配内存时,检测返回值是否为”空指针”是一个良好的习惯,可惜的是new在默认状态下,分配失败并不会返回一个空指针,而是抛出(throw)一个异常!!

对此正确的操作有如下两个方法:

①捕获异常

try{    _pb=new Bitmap(rhs._pb);      ...                     //其他操作}catch(const bad_alloc& e ){    return -1;}

②标准 C++ 亦提供了一个方法来抑制 new 抛出异常,而返回空指针

   int* p = new (std::nothrow) int;    // 这样如果 new 失败了,就不会抛出异常,而是返回空指针   if ( p == 0 ) // 如此这般,这个判断就有意义了       return -1;   ...           // 其它代码   delete p;
0 0
原创粉丝点击