3 资源管理 条款13~条款17
2015-11-27 19:22
218 查看
资源(文件描述器,互斥锁,图形界面中的字型和笔刷,数据库连接,以及网络sockets)就是一旦使用了它,将来必须还给系统。本章一开始是基于对象的资源管理方法,而管理内存的对象必须知道如何适当而正确的工作。
条款13:以对象管理资源
void f() { Investment * pInv = createTnvestment(); //调用factory函数,返回指针,指向Investment继承体系内的动态分配对象 ... delete pInv; //释放pInv所指对象 }
缺点:“...”区域中的一个过早的return语句或者中途抛出异常,若delete在循环中,有可能遇到continue,break或者goto语句而过早退出。无论哪种情况,我们最终泄露的不只是投资对象的那块对象,还包括那些投资对象所保存的任何资源,如string对象。
改进:我们需要将资源放进对象内,当控制流离开f时,该对象的析构函数会自动释放那些资源。如auto_ptr是个类指针对象。
<span style="font-size:10px;">void f(){ std::auto_ptr<Investment> pInv(creatInvestment()); ... } </span> //经由auto_ptr的析构函数自动删除pInv以对象管理资源的两个关键想法:1,获得资源后立刻放进管理对象,如调用createInvestment获得资源,放进auto_ptr对象中。 2,管理对象运用析构函数确保资源被释放。如管理对象离开作用域,其析构函数会被自动调用。
std::auto_ptr<Investment> pInv1(creatInveatment()); std::auto_ptr<Investment> pInv2(pInv1); //现在pInv2指向对象,pInv1被设为null pInv1 = pInv2; //现在pInv1指向对象,pInv2被设为null以上是auto_ptr的复制属性,导致没有一个以上的auto_ptr同时指向同一资源,可以引入“引用计数型智慧指针”RCSP,但RCSPs无法打破环状引用(两个没有被使用的对象互指,好像“被使用”。)
void f(){ ... std::tr1::shared_ptr<Investment> pInv1(createInvestment()); //pInv1指向createInvestment的返回物 std::tr1::shared_ptr<Investment> pInv2(pInv1); //pinv1和pInv2指向同一个Inveatment对象 pInv1 = pInv2; //同上,无任何改变 ... } //pInv1和pInv2被销毁,她们所指的对象也就自动被销毁auto_ptr和tr1::shared_ptr两者都在其析构函数内做delete而不是delete[]动作,故std::auto_ptr<std::string> aps(new std::string[10])从原则上看应该不合法。而在Boost中,boost::scoped_array和boost::shared_array classes都提供了这种分配数组的行为。我们也可以制作自己的资源管理类。最后,creatInvestment返回的“未加工指针”可能导致资源泄露,为防止忘记调用delete,可以将删除器绑定在智能指针上。
条款14:在资源管理类中小心coping行为
RAII:资源取得时机便是初始化时机,auto_ptr和tr1::shared_ptr用在heap资源上,而对于非heap资源,有时候需要建立自己的资源管理类。以下是用Lock类(资源管理类)来管理Mutex类(资源:互斥锁)void lock(Mutex *pm); //锁定pm所指的互斥器 void unlock(Mutex *pm); //将互斥器解除锁定 class Lock{ public: explicit Lock(Mutex *pm):mutexPtr(pm) { lock(mutexPtr); } //构造函数获得资源 ~Lock() { unlock(mutexPtr); } //析构函数释放资源 private: Mutex *mutexPtr; }; Mutex m; //定义你需要的互斥器 ... { //建立一个区块用定义critical section,临界区 Lock ml(&m); //锁定互斥器 ... //执行critical section内操作 } //在区块最末尾,调用析构函数自动解除互斥器锁定 Lock ml1(&m); //锁定ml Lock ml2(ml1); //将ml1复制到ml2身上,对于最后一句,我们选择以下两种可能:1,禁止复制,因为很少能够合理拥有“同步化基础器物”的副本。使用以下方法来禁止复制:
class Lock:private Uncopyable{ public: ... };
2,对底层资源使用“引用计数法”。有时候我们希望保有资源,直到它的最后一个使用者被销毁。故对于Lock类,可内含一个tr1::shared_ptr成员变量,由于我们用上一个Mutex,我们想要的释放动作是解除锁定而非删除。而tr1::shared_ptr允许指定所谓的“删除器”,当引用参数为0时便可调用,实现如下所示:
class Lock{ public: explicit Lock(Mutex *pm):mutex(pm, unlock) //以某个Mutex来初始化shared_ptr,并以unlock函数为删除器 { lock(mutexPtr.get()); } private: std::tr1::shared_ptr<Mutex> mutexPtr; };
此时Lock class没有必要再声明析构函数,因为mutexptr的析构函数会在互斥器的引用次数为0时自动调用tr1::shared_ptr的删除器。
对对象进行复制时,可1,复制底部资源,进行的是深度复制,如string对象的拷贝,须将成员变量中的指针指向的内存资源进行复制。2,转移底部资源的拥有权。资源的拥有权会从被复制物转移到目标物,如auto_ptr指针。
条款15:在资源管理类中提供对原始资源的访问
可以倚赖资源管理类来处理与资源之间的所有互动。std::tr1::shared_ptr<Investment> pInv(createInvestment()); int daysHeld(const Investment *pi); //返回投资天数 int day = daysHeld(pInv);此时没办法通过编译,因为函数需要将RAII class对象转换为其所含的原始资源的指针。以下有两种方法:
1,显式转换,tr1::shared_ptr和auto_ptr都提供了一个get成员函数来返回原始指针 int days = dayHeld(pInv.get());
2,隐式转换,tr1::shared_ptr和auto_ptr都重载了指针取值操作符(*和->),他们允许隐式转换成底部原始指针:
class Investment{ public: bool isTaxFree() const; ... }; Investment *createInvestment(); std::tr1::shared_ptr<Investment> pil(createInvestment()); bool taxable1 = !(pi1->isTaxFree()); //由智能指针转换为原始指针,再调用其成员函数,返回值为bool型 ... std::auto_ptr<Investment> pi2(createInvestment()); bool taxable2 = !((*pi2).isTaxFree());同理,对于大量与字体有关的C API,处理的是FontHandles,那么需要大量将Font转换为FontHandle。
1,显式转换,这个Font class类会增加泄露字体的可能性
2,隐式转换,增加了“非故意之类型转换”的机会
对原始资源的访问可能经由显式转换或隐式转换,一般而言显式转换比较安全,但隐式转换对客户比较方便。
条款16:成对使用new和delete时要采取相同的形式
条款17:以独立语句将newed对象置入智能指针
相关文章推荐
- 动态设置select与radio的默认值
- mysql表达式中decimal的设置,和length的设置
- 发布古典界面库 界面设计简简单单 不再饱受界面之虐
- 成为中间人的几种方式
- android 如何获得系统权限 android.uid.system
- UI图片轮转器
- 安卓签名工具SignApk.jar使用教程
- NYOJ 1112 求次数 (字符串)
- js和jsp变量互访的解决方法
- 循环中使用List.remove的坑
- AutoMapper中的Map和DynamicMap——高手注重细节,思考和总结
- eclipse 打开.java文件乱码
- CSS3教程:pointer-events属性值详解(转)
- hdoj--1301--Jungle Roads(克鲁斯卡尔)
- ZOJ 1610 Count the Colors (线段树区间更新)
- C中的volatile用法
- 广搜4 ——Cheese
- sign your own APK on your own OS
- AP算法实现解读
- Stanford机器学习---第十三讲.大规模机器学习