解决这个问题之前,我们要先理解一下C/C++为什么会出现这个问题,主要原因是C/C++有new和malloc这种内存管理机制能够让我们自由的管理我们的堆空间,这就需要我们及时的对空间进行申请和回收。
很多情况下,出现内存泄露的原因是我们对空间进行了申请但没有进行及时的回收。
这种情况常出现在在申请之后,程序出现了异常。所以没法回收。
所以,我们很自然的我们的最重要的解决办法:
把我们要管理的资源(指针)装进我们对象中
利用对象的析构函数来实现对资源的及时回收。这样,即使我们在new之后抛出了异常,也会自动调用管理资源的对象的析构函数,进行delete操作。
实际上,我们的auto_ptr()也是这样做的,上一小段书中的实例代码:
std::tr1::auto_ptr<Investment>
但是这样还是会引发一个问题,如果多个auto_ptr(自动指针)指向同一个对象的时候,会因为多次释放而导致出现意向不到的结果。这也是为什么auto_ptr在C++11被抛弃掉的原因。
于是,针对于多个对象同时引用的情况,我们有了新的shared_ptr智能指针,通过引用计数的方式,来回收资源。
所谓的引用计数,就是看对象之间的引用关系如何,每多一个对象引用这个智能指针,我们的引用计数就+1,释放就-1,直到为0,把智能指针delete掉。但这种情况更多是局部最优解,一旦出现两个对象相互成环引用就没法回收,如下图所示:
图中红色的两个点我们就没法回收到了。
解决办法在图中也表示出来了,这两个红色点明显是两个图中的不可达点。那么,我们只能回收图中的不可达点就好了。
还是把代码拿上来说下:
void f()
{
...
std::tr1::shared_ptr<Investment>
pInvl(createInvestment()); //pInv1指向
//createInvestment返回物。
std::tr1::shared_ptr<Investment>
pInv2(pInv1); //pInv1和pInv2指向同一个对象.
pInv1=pInv2; //同上,无任何改变.
...
} //pInv1和pInv2被销毁,它们所指的对象也就被自动销毁.
通过shared_ptr就只释放一次他们指向的同一个对象了。
这里还是需要提一个醒:
auto_ptr和shared_ptr实际上是将对象放进我们的资源管理对象里面的
所以说,理论上我们使用auto_ptr和shared_ptr是无法进行直接访问我们的原始对象的。
当时我们完善的C++怎么会让这种事情发生了呢,我们一共有两种方式:
1.通过get函数显式获取,如下代码:
int days=daysHeld(pInv.get())
2.auto_ptr和shared_ptr已经重载了operator->和operator*两个运算符,可以通过operator->和operator* 直接访问到我们的原始对象。
这里随便提一句,还有一种智能指针unique_ptr
unique_ptr表示的是指向的只能是单一的对象,不能指向多个对象。
最后再提一句,在删除对象的时候,一定要慎重是用delete 还是delete[]
如果我们用的是new,那么对应的就要使用delete
如果我们使用的是new 一个数组,那么对应的就要使用delete []
因为在我们使用delete 的时候,会跳用其的析构函数,要保证所有的析构函数都被调用,就要确定使用new 一个数组,然后使用delete [].