C++中的智能指针
1.为什么要使用智能指针?
先来看一段代码,分析这段代码有没有内存上的错误?
#include <iostream>
using namespace std;
void _MergeSort(int* a, int left, int right, int* tmp)
{
if (left >= right) return;
int mid = left + ((right - left) >> 1);
// [left, mid]
// [mid+1, right]
_MergeSort(a, left, mid, tmp);
_MergeSort(a, mid + 1, right, tmp);
int begin1 = left, end1 = mid;
int begin2 = mid + 1, end2 = right;
int index = left;
while (begin1 <= end1 && begin2 <= end2) {
if (a[begin1] < a[begin2])
tmp[index++] = a[begin1++];
else
tmp[index++] = a[begin2++];
}
while (begin1 <= end1)
tmp[index++] = a[begin1++];
while (begin2 <= end2)
tmp[index++] = a[begin2++];
memcpy(a + left, tmp + left, sizeof(int)*(right - left + 1));
}
void MergeSort(int* a, int n){
int* tmp = (int*)malloc(sizeof(int)*n);
_MergeSort(a, 0, n - 1, tmp);
// free(tmp);
}
int main()
{
int a[5] = {
4, 5, 2, 3, 1 };
MergeSort(a, 5);
return 0;
}
上面的问题分析出来我们发现有以下两个问题:
- 我们malloc开辟出来的内存空间,在程序结束前没有进行释放,存在内存泄漏的问题;
- 如果在malloc和free之间如果存在抛异常,那么还是有内存泄漏,这种问题就叫异常安全。
类似于malloc这样的问题,还有比如我们使用new来开辟内存空间,在程序结束之前也必须使用delete来释放。但当一个程序中频繁的使用内存空间,你能保证自己每一个手动开辟的内存块都释放了吗?在delete之前,倘若程序因为异常跳转后,你还能保证内存被释放吗?为了解决这种因为遗忘或者异常处理而导致内存泄漏的问题,我们就要用智能指针。
2.智能指针的使用及其原理
2.1RAII
RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。 借此,我们实际上把管理一份资源的责任托管给了一个对象。 这种做法有两大好处:
- 不需要显式地释放资源。
- 采用这种方式,对象所需的资源在其生命期内始终保持有效。
使用RAII思想设计的SmartPtr类:
// 使用RAII思想设计的SmartPtr类
template<class T>
class SmartPtr
{
public:
//构造对象时获取资源
SmartPtr(T* ptr = nullptr)
: _ptr(ptr){
}
//对象析构时释放资源
~SmartPtr(){
if(_ptr)
delete _ptr;
}
private:
T* _ptr;
};
void MergeSort(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int)*n);
SmartPtr<int> sp(tmp);
}
2.2智能指针的使用及原理
上述代码中的SmartPtr还不能称为智能指针,因为它还不具有指针的行为。指针可以解引用,也可以通过->去访问所指内存空间中的内容。因此AutoPtr类中还需要将*、->重载下,才能让其像指针一样去使用。
class SmartPtr
{
public:
SmartPtr(T* ptr = nullptr)
: _ptr(ptr){
}
~SmartPtr(){
if(_ptr)
delete _ptr;
}
w
T& operator*() {
return *_ptr;}
T* operator->() {
return _ptr;}
private:
T* _ptr;
};
具体使用:
#include<iostream>
using namespace std;
template<class T>
class SmartPtr
{
public:
SmartPtr(T* ptr = nullptr)
: _ptr(ptr){
}
~SmartPtr(){
if