copy-and-swap改进"异常安全"
来源:互联网 发布:淘宝开充话费店的知识 编辑:程序博客网 时间:2024/05/22 18:22
在了解到异常安全的重要性的重要性后,马上想到自己在刚学C++的时候,在单链表上所做的尝试,记得那个惨不忍睹的赋值函数是这样写的:
template <class Temp> LinkList<Temp> & LinkList<Temp>::operator=(LinkList<Temp> &List) { DestoryList(); LinkNode<Temp> *p = List.Head; LinkNode<Temp> *h = Head; while (p != NULL) { LinkNode<Temp> *t = new LinkNode<Temp>; if(t==NULL) { cerr << "error !" << endl; exit(1); } h->next = t; t->data = p->data; p = p->next; h = h->next; } return *this; }
如果new不抛出异常,正常的运行没什么大的问题,但是当new抛出异常时,那么就完蛋了。在抛出异常之前,原本的数据就已经被摧毁了,虽说会抛出异常,程序也会被终止(如果真能检测到的话,不过就上述代码似乎没什么机会),然而从“异常安全性”的角度来看,这个函数依旧是个非常糟糕的函数(其他问题先不提O(∩_∩)O~)
根据Effective C++ 中所述,“异常安全”需要满足两个条件
□ 不泄露任何资源
□ 不允许数据被破坏
而有效的异常安全函数(Exception-safe functions)提供如下三个保证之一:
★ 基本承诺: 如果异常被抛出,程序内的任何事物仍然保持在有效的状态下。没有任何对象和数据结构会因该函数调用而被破坏,所有对象都处于一种前后的一致状态。对于上述赋值函数,如果不对抛出的bad_alloc处理的话,那个这个单链表只剩一个空的头结点,虽然此时会指向一个不存在的结点,但是依旧保留了单链表的基本结构。
★ 强烈保证: 如果异常被抛出,程序状态不改变。调用这样的函数需要有这样的认知: 如果函数成功,就是完全成功;如果函数失败,程序回复到“调用函数之前的状态”的状态。(就像以前打BOSS之前先存个档,输了就读档一样)
★ 不抛出保证: 承诺绝不抛出异常,因为他们总是能够完成他们原先承诺的功能,比如给new提供一个nothrow保证。
从这里来看,似乎能够“读档”的强烈保证似乎是一个不错的保证,因此有必要了解一个有效的方法,这个策略被称为copy and swap。简单来说:为原本打算修改的对象(原件)作出一份副本,然后在那副本上做一切有必要的修改,若在修改的动作抛出异常,则保持原对象为改变的状态。待修改成功后,再将修改过的那个副本和原对象在一个不抛出异常的操作中置换(swap)。
对于copy and swap 策略来说,有两个重点
①copy
对原本的对象作出一份副本,在已经完成拷贝构造函数的前提下这是极为轻松的,也没什么可以多说的。
template <class Temp> LinkList<Temp>::LinkList(const LinkList ©) { LinkNode<Temp> *p = copy.Head->next; try { Head = new LinkNode<Temp>; LinkNode<Temp> *h = Head; while (p != NULL) { LinkNode<Temp> *t = new LinkNode<Temp>; h->next = t; t->data = p->data; p = p->next; h = h->next; } } catch (const bad_alloc & e) { cerr << "分配内存失败!" << endl; exit(1); } }
此时我们只需要在赋值函数中调用拷贝构造函数即可完成copy操作
LinkList<Temp> temp(*this);
②swap
对于交换而言可以说的东西确实不少,应该提出一个不抛出异常的swap函数,具体的构造方法详见 Efficetive c++ 条款25.对于我们的单链表,具体的实现如下
template<class Temp> void LinkList<Temp>::swap(LinkList<Temp> & other) { using std::swap; swap(Head, other.Head); } template<typename Temp> void swap(LinkList<Temp> & a, LinkList<Temp> & b) { a.swap(b); }
该专属swap与单链表类定义在同一个名称空间内。能够完成两个单链表对象的置换。
至此我们可以写成基于copy-and-swap的赋值函数
template <class Temp> LinkList<Temp> & LinkList<Temp>::operator=(LinkList<Temp> &List) { try { LinkList<Temp> temp(*this); temp.DestoryList(); LinkNode<Temp> *p = List.Head; LinkNode<Temp> *h = temp.Head; while (p != NULL) { LinkNode<Temp> *t = new LinkNode<Temp>; h->next = t; t->data = p->data; p = p->next; h = h->next; } swap(temp); return *this; } catch (const bad_alloc & e) { cerr << "error !" << endl; return *this; } }
“强烈保证”往往都能够以copy-and-swap实现,但是“强烈保证”并非对所有函数都可以实现。但确实也是一个很有意义的策略!
- copy-and-swap改进"异常安全"
- Copy-and-swap idiom详解和实现安全自我赋值
- Copy-and-swap idiom详解和实现安全自我赋值
- copy and swap
- Copy-and-swap
- copy and swap
- Copy-and-swap
- 【C++深入探索】Copy-and-swap idiom详解和实现安全自我赋值
- C++使用技巧:copy and swap idiom
- C++中的copy-and-swap idiom
- What is the copy-and-swap idiom?
- What is the copy-and-swap idiom?
- effective C++之copy and swap
- C++的 copy-and-swap idiom 是什么
- copy and swap技巧与移动赋值操作符
- C++ copy and swap (拷贝交换技术)
- The Rule of Big Three and half: Copy-and-swap Idiom
- copy,copy_backward,swap,transform
- JavaScript 开发的45个技巧
- AJAX POST&跨域 解决方案 - CORS
- 解决Xlistview 快速下滑时 头布局 会卡在屏幕上端 一半的位置不收回
- Activity内用handler更新TextView数据
- Loadrunner11-场景设置中的面向目标的场景设置的一点理解
- copy-and-swap改进"异常安全"
- 关于iOS中的弹出窗口----UIAlertController
- 读入一行以空格隔开的参数
- 【C++】:C++的命名规则
- 安卓常用开源库
- 飞信要退出了??
- Redis资料汇总专题
- Cross-Origin Resource Sharing[1] 跨域资源共享
- 自定义Switch滑动开关