异常安全之Copy and Swap(GeekBand第三周笔记)

上一周课程提到,在拷贝赋值中,需要检测自我赋值,一来是提高自我赋值时的效率,二来避免自我赋值中带有指针时,因为内存的释放导致的其它异常。当时有一个疑问,

自我赋值在实际代码编写中,并不常见,这样的检测,多了一层 if 语句判断,对于不是自我赋值的调用,岂不是降低了效率?

很快,第二周的作业中,又遇到新的问题。

异常安全之Copy and Swap(GeekBand第三周笔记)_第1张图片

图片上是自己写的cp op= 的实现。嗯,这里按照之前的学习,做了自我赋值的检测,但是,比对老师给出的评分标准,仍然踩到坑了,忘了判断other中的_leftup(Point*类型)指针是否为空。

异常安全之Copy and Swap(GeekBand第三周笔记)_第2张图片

很显然,这里的判断也是有必要的。吭哧吭哧的重构了自己的代码:

改过之后,似乎也不怕other._leftup== nullptr了。

可是,这才一个指针,就需要这样一堆的 if 做判断,如果Rectangle里边的指针再多一点,一个一个的判断下来,这效率该多底啊!!

有没有什么更好的办法呢?一头雾水。

说来也巧,翻阅《Effective C++》的时候,第29条,

Strive for exception-safe code.

书中提到,异常安全函数(Exception-safe functions)提供三种保证,基本承诺,强烈保证,不抛掷保证(non-throwing)。这里就不具体展开了。同时,书中还提到,有一个copy and swap设计策略,可以提供“强烈保证”。这个,就是这篇文章的重点了。

所谓copy and swap策略,就是从需要修改的对象拷贝(copy)一份,对这个副本进行修改,如果有任何异常,原对象不会有改变状态,如果修改成功,就把修改过的副本和原对象做一个置换(swap)。

按照这个策略,继续重构:

异常安全之Copy and Swap(GeekBand第三周笔记)_第3张图片
异常安全之Copy and Swap(GeekBand第三周笔记)_第4张图片

上面两张截图,保留了重构前后的代码。operator=的实现,只需要短短两行代码,other成员的判断,自我赋值的判断,通通不需要了。

这下,之前疑惑的几个问题,自我赋值判断的效率问题,代码冗余,都得到了很好的解决。那么,为什么可以这样呢?

这里其实有一个很重要的细节,参数不是pass by reference,而是pass by value。

我们应该知道,当初老师讲到,参数尽量pass by reference,因为不需要创建一个副本。也就是说,by value的时候,会提供一个副本。也就是说,一旦进入函数体,实际上我们已经调用拷贝构造,完成了一个到other副本的拷贝,这就提供了强烈的异常安全保证:如果拷贝失败,我们不会进入到函数体内,那么this指针所指向的内容也不会被改变。

进入函数体以后,other和this进行交换,this的数据放到临时对象里,这样在函数退出时,旧的数据自动被释放。


PS.以前只听说c++很难,现在发现一个难点所在了,各种各样的原则,策略,有些居然是互相矛盾的。在具体应用时,我们有更多的选择,但如何选择更合适的呢?这才是真正的难点所在。



本人其它笔记:

拷贝赋值中对自我赋值的检查(GeekBand第二周)


优雅的使用inline

你可能感兴趣的:(异常安全之Copy and Swap(GeekBand第三周笔记))