C++ 智能指针 — 创建简单的智能指针(学习笔记 一)

首次发文,多多包含,如有错误,请各位大神指正

在网上有很多相关的文章,我自己只是想写一个系列笔记是关于这个智能指针的实现,我会从零开始,然后,后面一步一步的验证我写的智能指针,我不对原理做解释及记录,因为网上有很多,那么我会直接通过代码来走,这个笔记也是我学习智能指针的过程,想学智能指针的初学者,可以参考

一、智能指针的设计与实现:引用计数

实现方式:

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

        至此,一个简单的智能指针已经实现了

猜你喜欢

转载自blog.csdn.net/acdfg123/article/details/118226287