3、资源管理
资源管理,一旦用了,就必须将其还给系统。资源包括动态内存分配,文件描述器,互斥锁,图形界面的字型,笔刷,数据库连接,网络sockets。
条款 13:以对象管理资源
遇到的问题:
void f()
{
Investment *pInv=createInvestment();
...
delete pInv;
}
在上述代码中,在heap上申请内存空间,然后经过“…”,然后使用delete释放申请的内存空间。
但是,在"…"的执行过程中,可能会存在return,抛出异常,或者发生在对createInvestment的使用及delete动作位于某个循环内,而该循环由于某个continue或goto语句过早退出。上述情况,使得delete语句不会执行,从而倒是内存泄漏。
解决方法:
- 将资源放入对象内,根据C++的析构函数自动调用机制确保资源被释放。
- 使用智能指针,shared_ptr对其进行管理,shared_ptr使用引用计数功能,当引用为0时,会自动释放申请的内存空间。
- 对于数组类型,使用c11中的array或者vector等stl的容器,他们不需要手动释放内存空间。
std::shared_ptr<Investment> createInvestment()
{
...
return make_shared<Investment>(...);
}
void f()
{
std::shared_ptr<Investment> pInv=createInvestment();
...
}
条款 14:在资源管理类中小心copying行为
遇到的问题:
并非所有的资源都是在heap上的,有时候需要建立自己的资源管理类。
class Lock{
public:
explicit Lock(Mutex *pm):mutexPtr(pm)
{
lock(mutexPtr);
}
~Lock(){unlock(mutexPtr);}
private:
Mutex *mutexPtr;
};
上面的代码是将互斥锁的函数进行了封装,我们只要创建对象,则在这个代码块中从这个对象创建起,将成为临界区。在脱离这个代码块时,将自动解锁。这个类遵循RAII原则,也就是”资源在构造期间获得,在析构期间释放“。
这里有几个问题:
当一个RAII对象被复制,会发生什么?
Lock ml1(&m);
Lock ml2(ml1);
- 禁止复制行为。
- 使用引用计数法。在类中使用shared_ptr对申请的内存空间进行管理。
class Lock{
public:
explicit Lock(Mutex *pm):mutexPtr(pm,unlock)
{
lock(mutexPtr);
}
private:
std::shared_ptr<Mutex> mutexPtr;
};