void f()
{
A* a=createA();
delete a;
}
这样写实际上很多情况都删除不了,比如提前退出了函数,抛出了异常,后续维护代码修改为提前return 。
所以利用对象的析构来管理内存资源
例子auto_ptr
void f()
{
std::auto_ptr<A> ptr(createA());
......
}
这就是RAII(Resource Acquisition Is Initialization)
但是需要注意指针不要指向同一个对象。不然会删除多次。
为了预防这个问题,auto_otr有一个不寻常的性质:若通过copy构造函数或copy assignment操作符复制它们,它们会变成null,而复制所得的指针将取得资源的唯一拥有权。
std::auto_ptr<A> ptr(createA());
std::auto_ptr<A> ptr2(ptr);//ptr会被设置为Null
std::auto_ptr<A> ptr=ptr2;//ptr2会被设置为null
这样的性质导致了一些局限性,有时候我们就是需要多个指针指向一个对象,然后只释放一次。
替代方案就是shared_ptr
void f()
{
std::tr1::shared_ptr<A> ptr(createA());
......
}
但是它打破不了环形引用。
auto_ptr和shared_ptr(一般都用这个),两者都在其析构函数内做delete而不是delete[]动作,所以不要在动态分配得到的array身上使用auto_ptr或tr1::shared_ptr
vector和boost::scoped_array和boost::shared_array都可以替代array。
如果资源不是在堆上,那么auto_ptr和tr1::shared_ptr就不适合了。
这种情况就需要自己建立资源管理类
例如
针对Mutex的lock和unlock,建立资源管理类Lock
class Lock{
public:
explicit Lock(Mutex* pm):mutenPtr(pm)
{
lock(mutexPtr);
}
~Lock(){unlock(mutexPtr);}
private:
Mutex *mutexPtr;
};
这样调用来使用
Lock m1(&mutex);
但是如果Lock被复制怎么办?
Lock m1(&m);
Lock m2(m1);
大多数时候有两种选择
class Lock{
public:
explicit Lock(Mutex* pm):mutenPtr(pm,unlock)
{
lock(mutexPtr.get());
}
private:
std::tr1::shared_ptr<Mutex> mutexPtr;
};
其它方式相对不常见
把智能指针转化为真实资源(普通指针)可以调用shared_ptr和auto_ptr的get成员函数。
也可以隐式(操作符->和*)这样来使用。
但是显式转换更受欢迎,不容易出错。
delete单一对象就是delete。
delete对象数组需要delete []。两个都必须严格对应原来的形式。
不要一句把new对象,智能指针构造函数放到一个地方去,而应该拆分。否则可能出现异常导致资源泄露
processA(std::tr1::shared_ptr<A>(new A),priority());//这是错误的。
//这是正确的
std::tr1::shared_ptr<A> pw(new A)
processA(pw,priority())
原因是执行顺序可能重排序。
错误的这一句可能是
priority出现异常了,new A对象就丢失了。