Effective C++ 条款13学习笔记:以对象管理资源

Use objects to manage resources
懈怠了几天,今天应该继续努力学习Effective C++ ,让自己每天充实起来。
资源对于我们计算机视为一个非常重要的概念。尤其我们第一时间想到的内存资源,当让资源还包括文件描述器,互斥锁,数据库连接,网络sockets等等。无穷尽的使用资源,最终一定会造成系统的崩溃,所以一定要记住:
无论那种资源,当你不再使用它的时候,必须要将他释放。
当我们写一些简单的程序的时候,我们明确到资源的删除和释放。但是,当我们的代码日渐膨胀的时候,条件判断逐渐增多的时候,我们对着自己的代码就会眼花缭乱。这个时候,你是否还记的,并清晰的释放资源呢。
下面我们使用一个例子来一步步模拟,如何对资源进行管理。

第一步,主动释放资源

先看代码示例

// Use_obj.cpp : 定义控制台应用程序的入口点。 //2011/9/16 by wallwind on revenco #include "stdafx.h" #include <iostream> using namespace std; class myClass { public: myClass() { cout<<"myClass()"<<endl; } }; int _tmain(int argc, _TCHAR* argv[]) { myClass *my=new myClass(); delete(my); system("pause"); return 0; }
下面来看看另一个较为复杂的例子:代码为随意写的,没有较严密的考虑到方法的封装性,这里是想验证代码。
// Use_obj.cpp : 定义控制台应用程序的入口点。 //2011/9/16 by wallwind on sunrise #include "stdafx.h" #include <iostream> using namespace std; class myClass { public: myClass() { cout<<"myClass()"<<endl; } ~myClass() { cout<<"~~myClass()~~delete"<<endl; } }; myClass * createmyClass() { return new myClass(); } void f() { myClass *pmyC=createmyClass(); /调用工厂函数 ///.........return ; delete pmyC; ///s删除所指对象 } int _tmain(int argc, _TCHAR* argv[]) { f(); system("pause"); return 0; }
图一,图二
从以上例子及我的注释中,我们都可以看到,如果在delete操作之前,我们就没有删除所指的对象,这时候就会在内存中留下了垃圾 ,类似情况发生在对 createmyClass的使用及delete动作位于某循环内,而该循环由于某个continue或goto语句过早退出。最后一种可能是“...”区域内的语句抛出异常,果真如此控制流将再次不会幸临delete。无论delete如何被略过去,我们泄漏的不只是内含投资对象的那块内存,还包括那些投资对象所保存的任何资源。
也许在开发之时,我们很谨慎的做了这些。但是,但我们的代码交付给一些人进行维护的时候,他们很有,可能会有某些人添加return语句或continue语句而未能全然领悟它对函数的资源管理策略造成的后果。更糟的是f的“...”区域有可能调用一个“过去从未抛出异常,却在被'改善'之后开始那么做”的函数。因此单纯依赖“f总是会执行其delete语句”是行不通的。
所以,我们现在有想法,就是当我们离开了函数f()的时候,该对象的析构函数会自动释放那些资源
实际上这正是隐身于本条款背后的半边想法: 把资源放进对象内,我们便可依赖C++的“析构函数自动调用机制”确保资源被释放。
第二步,让 auto_ptr管理资源
我们使用标准程序库提供的auto_ptr 类,对资源进行管理,因为C++中许多资源动态分配于heap内,auto_ptr 是一种智能指针,其析构函数自动对其所指对象调用delete。
// Use_obj.cpp : 定义控制台应用程序的入口点。 //2011/9/16 by wallwind on sunrise #include "stdafx.h" #include <memory> #include <iostream> using namespace std; class myClass { public: myClass() { cout<<"myClass()"<<endl; } ~myClass() { cout<<"~~myClass()~~delete"<<endl; } }; myClass * createmyClass() { return new myClass(); } void f() { auto_ptr<myClass> pmy(createmyClass()); } int _tmain(int argc, _TCHAR* argv[]) { f(); system("pause"); return 0; }
图三
从结果可以看出, auto_ptr自动调用了析构函数,进行对对象的删除。
这个简单的例子示范“以对象管理资源”的两个关键想法:
  • 获得资源后立刻放进管理对象内。以上代码中createInvestment返回的资源被当做其管理者auto_ptr的初值。实际上“以对象管理资源”的观念常被称为“资源取得时机便是初始化时机”,因为我们几乎总是在获得一笔资源后于同一语句内以它初始化某个管理对象。有时候获得的资源被拿来赋值(而非初始化)某个管理对象,但不论哪一种做法,每一笔资源都在获得的同时立刻被放进管理对象中。
  • 管理对象运用析构函数确保资源被释放。不论控制流如何离开区块,一旦对象被销毁(例如当对象离开作用域)其析构函数自然会被自动调用,于是资源被释放。如果资源释放动作可能导致抛出异常,事情变得有点棘手,但条款8已经能够解决这个问题,所以这里我们就不多操心了。
需要注意的是不要让多个auto_ptr指向同一个对象,否则该对象将会被释放多次,导致crash。不过auto_ptr的copy构造函数和copy assignment操作符可以避免这样的问题,
如果这样写的话
void f() { auto_ptr<myClass> pmy(createmyClass()); auto_ptr<myClass> pmy2(pmy); pmy = pmy2; }
第三步,使用更加智能指针管理
rscp(reference-counting smart pointer)也是智能指针,它可以跟踪有多少对象指向某个资源。使用它的条件是必须安装Visual C++ 2008 Feature Pack,里面才有tr1。rscp的行为和垃圾回收比较接近,只有指向同一对象的所有引用全部不存在时候,它才会进行删除。如下代码
// Use_obj.cpp : 定义控制台应用程序的入口点。 //2011/9/16 by wallwind on sunrise #include "stdafx.h" #include <stdlib.h> #include <memory> #include <tr1/memory> #include <iostream> using namespace std::tr1; using namespace std; class myClass { public: myClass() { cout<<"myClass()"<<endl; } ~myClass() { cout<<"~~myClass()~~delete"<<endl; } }; myClass * createmyClass() { return new myClass(); } void f() { shared_ptr<myClass> pmy(createmyClass()); shared_ptr<myClass> pmy2(pmy); pmy = pmy2; } int _tmain(int argc, _TCHAR* argv[]) { f(); system("pause"); return 0; }
使用智能指针,我们要注意的是auto_ptr和shared_ptr两者都是在析构函数里进行delete,而不是delete[]动作。那意味着动态分配而得的array身上使用auto_ptr和shared_ptr令人无能为力。但那样错误的行为却可以通过编译,导致无法预测的内存泄露。
请记住:

1、为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源。

2、两个常被使用的RAII classes分别是tr1::shared_ptr和auto_ptr。前者通常是较佳选择,因为其copy行为比较直观。若选择auto_ptr,复制动作会使它(被复制物)指向null。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值