《Effective C++》 第三章: 资源管理
admin
2024-05-21 17:04:35
0

文中段落序号对应着书中的item编号。本文介绍item 13~17

本章主要介绍资源管理的一些思想和技巧。

什么是资源?简要地说就是用了之后必须归还的事物,比如说new申请的堆内存、文件、数据库连接、互斥锁等等。这些资源容易出现一些问题(比如使用后忘了释放),利用C++的一些机制可以有效避免。

13. 使用类来管理资源

先看这样一段代码:

Investment* createInvestment();//动态申请一个Investment对象,返回对象的指针void f()
{
Investment *pInv = createInvestment();
/*一些操作*/
delete pInv;
}

函数f在执行时先申请了一个Investment对象,最后回收。看起来这没什么问题,对吧?

问题是中间的一些操作,万一里面有return、exit、throw等等呢?类似的还有在循环体中的break、continue等。听起来这是正常人不会犯的低级错误,但是假如代码非常复杂呢?假如有个不很了解这段代码的人半路接手了这个代码呢?假如你时隔一年之后已经忘了自己怎么实现的,但又想优化一下代码呢?

这些事情非常容易发生。不过幸好,我们可以借助C++的类机制来管理这些资源。比如说将申请资源的代码写在构造函数中,释放资源的代码写在析构函数中。因为析构函数会自动调用,我们可以在析构函数中自动地回收资源。

auto_ptr

auto_ptr是一个管理指针的对象。
如果使用auto_ptr来优化前面的f函数,就变成了下面这样

void f()
{
std::auto_ptr pInv(createInvestment()); 
/*一些操作*/
}

pInv会在析构时自动delete Investment的指针。
不过要小心指针被重复delete的问题。假如有两个auto_ptr保存着同样的指针,那么该指针会被重复delete。
另外一个奇怪的地方是auto_ptr赋值后赋值的一方指针会变成null(拷贝构造函数同理)。

std::auto_ptr  pInv1(createInvestment()); 
std::auto_ptr pInv2(pInv1); // pInv1现在变成null
pInv1 = pInv2; // pInv2变成null

由于STL的底层需要用到正常的赋值操作,auto_ptr不适合使用STL。

shared_ptr

shared_ptr是一个引用计数智能指针(reference-counting smart pointer)。它会自动统计每个生成的对象有多少的引用,当引用数为0时再回收该对象。听起来像是垃圾回收机制,不过它不能处理环状引用问题。

void f()
{
...
std::tr1::shared_ptr
pInv(createInvestment());
/*一些操作*/
}

shared_ptr的赋值和拷贝构造函数就正常多了,也可以用在STL中。

auto_ptr和shared_ptr不能用于数组

auto_ptr和shared_ptr中的资源回收都是通过delete实现的,而不是delete[]。 也就是它不可以回收数组。

14. 自定义资源管理类

auto_ptr 和tr1::shared_ptr功能比较有局限性,很多时候我们需要创建自己的资源管理类。
以互斥锁为例。

void lock(Mutex *pm); // lock mutex pointed to by pm
void unlock(Mutex *pm); // unlock the mutex

如果不借助类,互斥锁应当这样实现:lock→临界代码区→unlock
如果借助资源管理类的实现如下所示:
定义类:

class Lock {
public:
explicit Lock(Mutex *pm)
: mutexPtr(pm)
{ lock(mutexPtr); } // acquire resource
~Lock() { unlock(mutexPtr); } // release resource
private:
Mutex *mutexPtr;
};
Mutex m; //定义互斥量
...
{
Lock ml(&m); //加锁
... //临界区
}

赋值/拷贝的处理

在前面的例子中,假如对Lock进行拷贝会怎么样?

Lock ml1(&m); // lock m
Lock ml2(ml1);

在资源管理类中,对于拷贝和赋值必须小心。通常有以下策略。

    1. 不允许拷贝。将拷贝构造函数设置为private
    1. 引用计数。类似于tr1::shared_ptr的策略,只有当计数为0时再回收。这个方案可以用到tr1::shared_ptr,一个例子如下:
class Lock {
public:
explicit Lock(Mutex *pm) // 
: mutexPtr(pm, unlock) // mutexPtr销毁时会调用unlock,而不是delete
{ 
lock(mutexPtr.get()); // item15会介绍"get"
}
private:
std::tr1::shared_ptr mutexPtr; 
};
    1. 移交所有权。 类似于auto_ptr的实现,a=b则b不再占有该资源。
    1. 彻底地复制。通常需要深复制,确保不会出现差错。

15. 提供访问原始资源的函数

将资源封装成类之后,经常有必要提供一个对原始资源的访问函数:因为有可能会用到这些原始资源。(书中对这部分讲得比较啰嗦,我感觉其实不需要多解释这个问题)

不过一个需要思考的问题是:原始资源以怎样的方式暴露在外?
以下几个方法值得考虑:

  1. 使用一个get函数
  2. 重载对象的行为,使之和所管理的资源一致。
  3. 重载强制转换函数,使得封装对象可以转换为原始资源。这里需要注意是否允许隐式转换。

当然这几点并没有最佳做法,关键是视资源的使用环境而定。

16. new 和delete要匹配

如果是new int[10], 对应delete []
如果是new int, 对应delete.

一定要注意匹配。

如果使用了typedef,一个变量可能看起来是单个元素实际上是一个数组,delete时尤其要注意。

17. 在使用对象封装资源时请使用独立的语句

先看一个反例:

/*
已知函数:
int priority();
processWidget(std::tr1::shared_ptr widget, int priority);
*/
processWidget(std::tr1::shared_ptr(new Widget), priority());

这一行代码可以通过编译,但其实是比较危险的。原因在于写在函数参数中的语句并没有确定的执行顺序

在执行processWidget函数时,实际的调用顺序可能是:

  • new Widget
  • priority()
  • std::tr1::shared_ptr(Widget* )
  • processWidget( param*)

假如priority()函数抛出异常,new Widget的资源就被泄漏了。

所以正确的写法是:

std::tr1::shared_ptr pw(new Widget); 
processWidget(pw, priority()); 

相关内容

热门资讯

重庆渝中文旅致歉,回应游客称在... 13日清晨,渝中文旅发布情况通报: 近日,获悉洪崖洞景区附近因揽客拍照引发纠纷,重庆市渝中区文化旅游...
敦煌藻井配色:姜黄×钴蓝的东方... 敦煌藻井配色:姜黄×钴蓝的东方色彩应用手册 在莫高窟第407窟的藻井中央,两只飞天正驾着祥云穿越时光...
蓝牙耳机能够听手机里的所有声音... 蓝牙耳机能够听手机里的所有声音吗可以的。我手机千千静听放歌就可以从蓝牙耳机里听到,手机调静音的话耳机...
暖心救助显真情,水洞沟景区工作... 近日,银川市水洞沟景区发生了一件温暖人心的好人好事,景区工作人员的快速反应和无私帮助赢得了游客的深情...
普陀山香会节单日客流突破15.... 新京报讯(记者吴梦真)近日,浙江普陀山香会节迎来朝圣高峰。新京报记者从舟山海事局获悉,截至13日12...
清凉游、非遗赛事……多彩假日解... 天气炎热,很多人选择戏水消解暑意。为了满足游客需求,黑龙江省集贤县将冬季玩雪胜地改造成森林高山漂流、...
超限猎兵凯能atf种类 超限猎兵凯能atf种类为什么让凯恩战死?第一季的主角机:前导凯能、近战凯能和重装凯能第二季:前锋凯能...
原创 走... 2023年11月16日,我启动洩湖镇全域采风前期准备工作。当日午后,先后赴簸萁掌村和铧咀坪村与村委会...
守望的天空 守望的天空守望的天空,这部电视剧结局是什么样的?葡萄和墨理在一起了,大志和韩佩佳,小露和麦克。袁望同...
17.18岁的小男孩适合做什么... 17.18岁的小男孩适合做什么工作,最好是可以边学点技术的?17岁的话,也就差不多初中刚毕业的年龄,...
三国争霸锦囊道具 三国争霸锦囊道具我想知道起凡三国争霸里所有锦囊能开出来的但在店里买不到的装备属性分别介绍要全面哦烈4...
敬谢不敏是什么意思 ? 敬谢不敏是什么意思 ?敬谢不敏,谢:推辞;不敏:不聪明,没有才能。恭敬地表示自己能力不足,不能够接受...
拿刀割脚是什么成语 拿刀割脚是什么成语成语有“削足适履”,鞋小了,拿刀把脚去一点,以适合穿上,形容主次颠倒,应该是由鞋去...
“云上那达慕”开启百里荒帐篷露... 搜狐号消息 记者 项俊平 武汉报道 草地上摔跤,马背上夺羊......7月12日,随着“云上那达慕盛...
淅川:露营音乐季引爆夏日旅游热... 河南日报社三农全媒体中心记者 曹怡然 见习记者 高磊 通讯员 李金杭 7月12日,淅川县毛堂乡龙腾松...
谐音故事的简介 谐音故事的简介 谐音故事:在作文中使用时,会给大家带来幽默感。
如果有人统一四大基本力,那么他... 如果有人统一四大基本力,那么他在科学界是不是最伟大的?统一四大晌明基本力的人是科学界最伟大的。目前还...
我是深圳小主人(大运会的) 我是深圳小主人(大运会的)字不要太多、100—50就行了少时诵诗书少时诵诗书做大运小主人大事小事天下...
像"完壁归赵&quo... 像"完壁归赵"这样的历史故事成语还有吗?要带上作者!作业啊``烦死了!!三顾茅庐 刘备