天天看点

Effective C++ 学习笔记 《十三》Item 13: Use objects to manage resources.

Item 13: Use objects to manage resources.

看到这个item就明白是关于资源管理的,众所周知,内存泄漏是c++典型的一种坑,自然而然对内存泄露的避免是一个非常有意义的话题。

所以这一节的重要性尤其突出。

如题,作者给出的建议就是用对象来管理资源 书上首先给了个例子

void f()
{
	Investment *pInv = createInvestment(); // call factory
	function
 	... // use pInv delete pInv; // release object
 	delete pInv;
}

Investment* createInvestment(); // return ptr to dynamically allocated object in the Investment hierarchy;
								// the caller must delete it (parameters omitted for simplicity)
           

这段代码首先动态分配了一块内存,使用完之后delete,看起来好像没什么问题,但是我们不得不考虑如果代码没有执行到delete,也就是说在delete之前因为各种原因,比如异常,比如提前return等等导致这个指针的资源没有被释放掉,这意味着这段代码是存在内存泄露的风险。

其实这个问题很常见,我们常听说写C++最应该避免的就是写一堆delete,原因就在这。

解决问题的办法就是把资源放进对象中来管理,基于对象自动调用析构函数的机制就能避免。比如智能指针就是典型的例子。其实这也是著名的RAII思想,即得到资源的时候便进行初始化。因为通常我们得到某种资源的时候,就会用这个资源来初始化或者是赋值给某个对象,无论哪种都应该在获得资源的时候就把它放到管理对象中。

同时管理对象应该保证资源能被释放,一旦对象被销毁比如离开作用域,它的析构函数就应该自动被调用然后释放资源。

接着书上就提到了智能指针的例子,首先是老版的auto_ptr, 书上说到不能让多个auto_ptr指向同一个对象,否则多个auto_ptr就会多次对同一块内存进行释放。为了避免这个问题,auto_ptr用一个奇怪的性质,就是不允许共享,也就是当复制一个auto_ptr给其他auto_ptr,那么被复制的对象就会变成NULL,得到的新指针反而会得到这个对象,相当于发生了一次转移。

std::auto_ptr<Investment> // pInv1 points to the
pInv1(createInvestment()); // object returned from createInvestment
std::auto_ptr<Investment> pInv2(pInv1); // pInv2 now points to the object; pInv1 is now null
pInv1 = pInv2; // now pInv1 points to the object, and pInv2 is null
           

比如pInv2 被赋值之后,pInv2就指向这个对象,原先的pInv1就变成了NULL,下面的语句也会发生类似的效果。

这个现象就导致auto_ptr其实不好用,因为不支持正常的复制的话,stl容器就用不了了。

接着提到了计数型指针,其实就是shared_ptr,它满足可以多个指针引用同一对象从而解决这个问题。

另外作者强调不要用shared_ptr来保存一个数组,原因就是它只会调用delete而不是delete [ ],对于数组资源,有好用的vector和string这种,所以不需要刻意来考虑用shared_ptr管理。

作者花了很大篇幅来讲智能指针其实还是想强调通过对象来管理资源的思想。总结这一节最重要的思想还是RAII,简单说就是在构造函数中获得资源,在析构函数中释放资源,同时考虑使用智能指针。

继续阅读