首次发文,多多包含,如有错误,请各位大神指正
在网上有很多相关的文章,我自己只是想写一个系列笔记是关于这个智能指针的实现,我会从零开始,然后,后面一步一步的验证我写的智能指针,我不对原理做解释及记录,因为网上有很多,那么我会直接通过代码来走,这个笔记也是我学习智能指针的过程,想学智能指针的初学者,可以参考
一、智能指针的设计与实现:引用计数
实现方式:
1.首先创建智能指针的类,用于保存新建的数据
#pragma once
#include <assert.h>
#include <memory>
//智能指针:引用计数
template<typename T>
class CSharedPtr
{
public:
/*
* 当创建全新的类时,进行保存,并创建计数
*/
CSharedPtr(T* ptr)
:T_Ptr(ptr)
{
T_Count = new size_t(1);
}
//拷贝构造的时候,引用+1,而不是创建新的
CSharedPtr(const CSharedPtr& ptr)
{
if (this != &ptr)
{
T_Ptr = ptr.T_Ptr;
T_Count = ptr.T_Count;
++(*T_Count);
}
}
//重载=
CSharedPtr& operator=(const CSharedPtr& ptr)
{
if (T_Ptr == ptr.T_Ptr)
return *this;
(*ptr.T_Count)++;
if (T_Ptr && (--(*T_Count) == 0 ))
{
delete T_Ptr;
delete T_Count;
}
T_Ptr = ptr.T_Ptr;
T_Count = ptr.T_Count;
return *this;
}
~CSharedPtr()
{
if (--(*T_Count) == 0)
{
delete T_Ptr;
delete T_Count;
}
}
inline size_t GetCount(){ return *T_Count; }
private:
T* T_Ptr;
size_t* T_Count;
};
2.创建一个测试类,在析构函数里添加打印数据
#pragma once
#include <iostream>
#include <cstring>
class TestA
{
public:
TestA(const std::string inName):_name(inName),_val(-1){}
TestA(const std::string inName,int inVal):_name(inName),_val(inVal){}
~TestA()
{
std::cout<<"~TestA: create class name: " <<_name<< ": " <<_val << std::endl;
}
private:
std::string _name;
int _val;
};
3.然后在main 函数里进行测试
#include "CSharedPtr.h"
#include "TestA.h"
#include <iostream>
int main()
{
//添加域,用以测试,类被析构和调用的情况
{
CSharedPtr<TestA> _A(new TestA("_A"));
CSharedPtr<TestA> _B(_A);
CSharedPtr<TestA> _C(new TestA("_C",10));
_C=_B;
std::cout << "A:"<< _A.GetCount() << std::endl;
std::cout << "B:"<< _B.GetCount() << std::endl;
std::cout << "C:"<< _C.GetCount() << std::endl;
}
return 0;
}
当运行程序时:得出的结果为:
其中:
第一个结果:~TestA: create class name: _C: 10 是在 _C = _B 的时候进行一次调用,这个过程会调用智能指针的 重载= 操作函数: CSharedPtr& operator=(const CSharedPtr& ptr)
因为 _C 仅有一次引用计数(创建时),所以当被赋予新的值时,引用计数为0,即T_Count=0 所以,_C原来创建的数据就会被 delete 掉,被delete掉就会调用TestA的析构函数,从而打印出 ~TestA: create class name: _C: 10
第2、3、4行的结果是,引用计数的结果,之所以都是3,是因为,3个类,他们保存的地址都是同一个,就是第一个创建的 _A;
为什么保存的地址都是 _A呢?
我们来分析一下这个过程:
首先:CSharedPtr _A(new TestA("_A")); // 这是第一次创建(此时引用计数为1)
CSharedPtr _B(_A); //这是一智能指针里的拷贝构造,它会把_A 的智能指针数据,赋值到 _B上,同时进行一次引用计数,查看函数:CSharedPtr(const CSharedPtr& ptr)
到目前为止,_A的引用计数已经为 2
第三次的引用计数,发生在 _C = _B; 的过程,可以查看智能指针类里的 重载= 函数
当执行完 _C=_B 后 _A的引用计数已经达到3次,从而导致 2、3、4行的打印结果为 都为 3
最后打印的析构数据,是因为,到了析构的时候,仅剩下_A
至此,一个简单的智能指针已经实现了