C++11提供了智能指针用于动态管理堆空间的内存分配与释放,通过维护智能指针这个栈对象使得当智能指针离开作用域时能够自动释放其管理的内存。
其中,最常用的应该是shared_ptr, 提供了共享语义,也即多个指针共享同一个资源。
实现原理维护一个指向资源的裸指针以及引用计数指针(都属于堆空间)。当智能指针离开作用域时,引用计数-1,当新生成一个智能指针时,引用计数+1,只有当引用计数=0时才会释放智能指针管理的内存空间。
下面来看下shared_ptr的实现细节吧。
#include <bits/stdc++.h>
using namespace std;
template <typename T>
class my_shared_ptr{
public:
my_shared_ptr(T * t);
~my_shared_ptr();
my_shared_ptr(const my_shared_ptr<T> & origin);
my_shared_ptr <T> & operator=(const my_shared_ptr<T> & origin);
public:
T * get(){
return row_ptr;
}
T operator *()
{
return * row_ptr;
}
T * operator ->()
{
return row_ptr;
}
private:
T * row_ptr = nullptr;
int * count = nullptr;
};
template <typename T>
my_shared_ptr<T> :: my_shared_ptr(T * t)
{
row_ptr = t;
try{
count = new int(1);
}
catch(...)
{
delete row_ptr;
row_ptr = nullptr;
delete count;
count = nullptr;
cout << "Allocate memory for count fails" << endl;
exit(1);
}
cout << "constructer is called" << endl;
}
template<typename T>
my_shared_ptr<T> :: ~my_shared_ptr()
{
if(--(*count)==0)
{
delete row_ptr;
row_ptr = nullptr;
delete count;
count = nullptr;
cout << "deconstructer is called" << endl;
}
}
template<typename T>
my_shared_ptr<T> :: my_shared_ptr(const my_shared_ptr<T> & origin)
{
row_ptr = origin.row_ptr;
count = origin.count;
(*count)++;
cout << "copy constructer is called" << endl;
}
// first free then copy
template<typename T>
my_shared_ptr<T> & my_shared_ptr<T>::operator= (const my_shared_ptr<T> & origin)
{
(*origin.count)++;
if(--(*count)==0)
{
delete row_ptr;
delete count;
}
row_ptr = origin.row_ptr;
count = origin.count;
cout << "Assignment operator overload is called" << endl;
return *this;
}
注意点:
- 拷贝赋值函数中需要先释放原有资源,为了避免自身赋值这种情况,先将(*origin)++;
- delete指针释放资源之后,需要将指针置为nullptr
- 只有指针参数的构造函数中,引用计数指针需要通过new分配内存,通过try_catch处理堆空间不足的异常。