Effective C++读书笔记(3)——资源管理

资源的概念是一旦使用了该资源,将来就必须还给系统,不然就会产生不确定的行为。
C++中最常使用的资源就是动态分配内存,但还有其他的资源比如文件描述器、互斥锁、图形界面的字型和笔刷、数据库连接以及网络socket。

以对象管理资源

以对象管理资源的话,主要是有两种关键的想法:
获得资源之后立刻放进管理对象(RAII机制)
管理对象运用析构函数来确保资源被释放—在析构函数中的资源释放可能会抛出异常,需要把异常吞掉。

//RAII
class Investment{...};
//使用工场函数返回一个特定的Investment对象
Investment* createInvestment();

//其实感觉RAII的使用之一就是多使用智能指针
void f(){
	std::auto_ptr<Investment> pInv1(createInvestment());		//使用智能指针的话会经由auto_ptr的析构函数来自动删除pInv
	std::auto_ptr<Investment> pInv2(createInvestmemt());
	pInv1 = pInv2;				//此时pInv1指向对象,pInv2为null
	...
}
//但是由于auto_ptr被销毁的时候会自动删除掉它所指之物,所以不允许将auto_ptr同时指向同一个对象
//对auto_ptr使用copying函数(copy构造函数与copy assignment操作符)会将auto_ptr变成null(以获得资源的唯一拥有权)


//但有的时候会要求发挥正常的复制行为,这样的话,就可以使用tr1::share_ptr
//即引用计数型智慧指针(RCSPs),持续追踪有多少对象指向某笔资源,在无人指向它的时候自动删除(无法打破环状引用)

void f(){
	std::tr1::share_ptr<Investment> pInv1(createInvestment);
	std::tr1::share_ptr<Investment> pInv2(createInvestment);
	pInv1 = pInv2;				//两者指向同一个对象
}

auto_ptr与trl::share_ptr的析构函数做的是delete行为而非delete[ ]行为,所以不能将这两个智能指针用于array上面(但这个行为会通过编译)。

void f(){
	std::auto_ptr<std::string> aps(new std::string[10]);		//错误行为!!!
}
//如果需要使用,建议使用boost::scoped_array和boost::share_array

在资源管理类中小心copying行为

上述的使用auto_ptr与tr1::share_ptr来进行管理资源是基于该资源是heap-base的。如果对于非heap-base上的资源来说这些智能指针就不适合作为资源管理者,此时可以建造一个资源管理的类来进行资源管理。

堆跟栈的区别

//互斥锁的资源管理类
class Lock{
public:
	explicit Lock(Mutex* pm) : mutexPrt(pm)
	{ lock(mutexPtr); }				//获得资源
	~Lock() { unlock(mutexPtr); }	//释放资源
private:
	Mutex *mutexPtr;
};

由于复制RAII类的对象的时候使用的是深度拷贝,这时候连同类所管理的资源也一并复制,所以资源的copying行为决定了RAII对象的copying行为。
常见的应对RAII类的copying行为是抑制copy和施用引用计数法。

//使用继承一个无法复制的类来禁止复制
class Lock: private Uncopyable{
	...
};

//使用引用计数法---类似于tr1::share_ptr,实际操作也是在类中使用一个tr1::share_ptr的成员变量来实现
//使用引用计数法的话可以保有资源直到最后一个使用者
class Lock{
public: 
	//此处的mutexPtr第二个参数unlock是指定unlock为删除器,auto_ptr并不能指定删除器
	explicit Lock(Mutex* pm) : mutexPtr(pm,unlock)
	{
		lock(mutexPtr.get());
	}
private:
	std::tr1::shared_ptr<Mutex> mutexPtr;
};

在资源管理类中提供原始资源的访问

有的时候我们需要将RAII对象转化为原始的资源,书上提出了两个做法,显式转换与隐式转换:

//tr1::share_ptr和auto_ptr都提供了一个get函数成员,用来执行显示的转化
std::auto_ptr<Investment> pInv(createInvestment());
pInv.get();					//返回一个智能指针内部的原始指针副本

//所有的智能指针也重载了指针取值操作符(operate->和operate*)的功能,他们允许隐式转换成原始指针
class Investment{
public:
	isTest();
};

std::auto_ptr<Investment> pInv1(createInvestment());

pInv1->isText();
(*pInv1).isText();

APIs往往要求访问原始资源,所以每个RAII类应该提供一个返回资源的方法。
对于这种返回资源的方法来说,一般是要显示转换会比隐式转换安全一点(避免增加发生错误的机会)。

成对使用new与delete

如果使用new就要用delete。
如果new中使用[ ],那么相应的delete也要使用[ ]。

std::string* stringArray = new std::string[10];
delete[] stringArray;		//如果使用delete的话,后面的9个string对象可能不会删掉。

以独立语句将newed对象置入智能指针

C++编译器对于参数的核算顺序是不确定的,所以如果在智能指针中进行new操作的话可能会导致内存泄漏。

processWidget(std::trl::share_ptr<Widget>(new Widget),priority());//可能会导致资源泄露

std::tr1::share_ptr<Widget> pw(new Widget)processWidget(pw,priority());		//不会造成泄露

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值