实现过程
1.指针计数类
class PtrCounter
{
public:
PtrCounter(): count{1} {}
void add(){++count;}
void subtract(){--count;}
int get() const{return count;}
private:
std::atomic<int> count;
};
STL提供的共享指针基于引用计数原理,故我们也先定义这样一个指针引用计数类。该类包含三个成员函数,分别为计数加一add()函数,计数减一subtract()函数,和获取计数值 get()函数。还有一个用原子类型封装的私有整型成员变量,初始值为1,它的访问保证不会导致数据的竞争,并且可以用于在不同的线程之间同步内存访问。
2.共享指针模板类
template<typename T>
class SharePtr
{
public:
SharePtr(T* ptr) : my_ptr{ptr}, my_ref_count{new PtrCounter} {}
SharePtr() : my_ptr(nullptr),my_ref_count(new PtrCounter){}
SharePtr(const SharePtr &p)
{
this->my_ptr = p.my_ptr;
this->my_ref_count = p.my_ref_count;
my_ref_count->add();
}
SharePtr& operator = (const SharePtr &p)
{
clear();
this->my_ptr = p.my_ptr;
this->my_ref_count = p.my_ref_count;
my_ref_count->add();
return *this;
}
SharePtr(SharePtr &&p)
{
this->my_ptr = p.my_ptr;
this->my_ref_count = p.my_ref_count;
p.my_ptr = nullptr;
p.my_ref_count = nullptr;
}
SharePtr &operator =(SharePtr &&p)
{
clear();
this->my_ptr = p.my_ptr;
this->my_ref_count = p.my_ref_count;
p.my_ptr = nullptr;
p.my_ref_count = nullptr;
return *this;
}
~SharePtr(){clear();}
int use_count() {return my_ref_count->get();}
T* get() const {return my_ptr;}
T* operator->() const {return *my_ptr;}
T& operator*() const {return *my_ptr;}
operator bool() const {return my_ptr;}
private:
T* my_ptr;
PtrCounter* my_ref_count;
void clear()
{
if(my_ref_count)
{
my_ref_count->subtract();
if(my_ref_count->get() == 0)
{
if(my_ptr) delete my_ptr;
delete my_ref_count;
}
}
}
};
接着是共享指针核心类。该类有两个私有成员指针变量分别为指针引用计数类型指针和模板参数类型指针。类重载了两个构造函数,一个传模板参数类型指针参数,一个未带参数,在构造函数里都对成员变量做了初始化。拷贝构造进行浅拷贝并引用计数加一,赋值函数在进行浅拷贝之前会先做一个重要的清除操作,该操作先将指针引用计数减一,并判断指针引用计数是否为0,若是,则delete 掉两个指针成员变量。另外定义了移动拷贝构造函数和移动赋值函数,这两个函数和前两个构造函数和移赋值函数的区别在于是否将模板参数类型指针成员变量置为空。最后是析构函数,做清除操作。
测试
struct A
{
A() {std::cout<<"A()\n";}
~A(){std::cout<<"~A()\n";}
};
void test_sharePtr()
{
A* a = new A;
SharePtr<A> ptr(a);
{
std::cout<<ptr.use_count()<<std::endl;
//调用拷贝构造函数
SharePtr<A> b= ptr;
std::cout<<b.use_count()<<std::endl;
std::cout<<ptr.use_count()<<std::endl;
SharePtr<A> c;
//调用赋值函数
c = ptr;
std::cout<<c.use_count()<<std::endl;
std::cout<<ptr.use_count()<<std::endl;
}
std::cout<<ptr.use_count()<<std::endl;
}
测试结果: