c++三种智能指针以及相关知识自写智能指针

Posted 头号理想

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++三种智能指针以及相关知识自写智能指针相关的知识,希望对你有一定的参考价值。

传统指针存在的问题

当我们在堆上创建了一个对象的时候,如果我们用完,系统并不会回收资源,必须我们手动来释放它
如果我们没有处理好申请和释放的问题,那么可能造成内存泄漏的情况(没有释放/多次释放)

shared_ptr

每种指针都是以类模板的方式实现的,shared_ptr也不例外,
shared_ptr(T是指针指向的具体数据类型)的定义位于头文件,并且位于std命名空间中

#include<memory>
using namespace std;

和unique_ptr以及weak_ptr指针不同的地方在于:
多个shared_pt智能指针可以使用同一块堆内存,并且该类型只能指针在实现上采用的是引用计数机制
即使有一个shared_ptr放弃了堆内存的使用权 (引用计数减1) 也不会影响其他shared_ptr的使用 只有引用计数为0 堆内存才会释放

shared_ptr的创建

	std::shared_ptr<int> p1;//不传入任何实参
	std::shared_ptr<int> p2(nullptr);//传入空指针(c++11新特征)
	std::shared_ptr<int> p3(new int(10));//明确指向
	std::shared_ptr<int> p4 = std::make_shared<int>(10);//模板函数 c++11新特征

空的 shared_ptr 指针,其初始引用计数为 0,而不是 1。

同时 shared_ptr模板还提供了相应的构造函数和移动构造函数

std::shared_ptr<int> p5(p3);//调用拷贝构造函数
std::shared_ptr<int> p6(std::move(p4));//调用移动构造函数

同一指针不能同时为多个shared_ptr对象赋值,否则会导致程序发生异常

为了用户方便使用shared_ptr指针,shared_ptr模板类还提供了一些实用的成员方法


同时c++11新标准还支持同一类型的shared_ptr的对象货真shared_ptr之间进行== != >= <= > < 等的运算

实例


int main() 
	std::shared_ptr<int> p1(new int(10));
	std::shared_ptr<int> p2(p1);
	cout << "*p2" <<"  "<< *p2 << endl;

	p1.reset();//引用计数减1 p1成为空指针
	if (p1) 
		cout << "p1不为空指针" << endl;
	
	else 
		cout << "p1是空指针" << endl;
	

	//以上操作不会影响p2
	cout << "*p2" << "  " << *p2 << endl;
	cout << p2.use_count() << endl;


unique_ptr

unique_ptr也具备“在适当的时机自动释放堆内内存空间”的能力
和shared_ptr最大的不同之处就是在于 unique_ptr指针指向的堆内存无法将其与其他unique_str共享
也就是说unique_ptr指针都独自拥有对其所指堆内存空间的所有权

这也就是说 每个unique_str指针指向的堆内存空间的引用计数就是只能为1
一旦该unique_ptr指针放弃所致堆内存空间的所有权,该空间会被立即释放回收

unique_ptr和shared_ptr一样 模板类也提供了一些成员方法


实例


int main() 
	std::unique_ptr<int> p5(new int);
	*p5 = 100;
	int* p = p5.release();//释放当前对所指堆的使用权 但不会销毁存储空间
	//p接收p5释放的堆内存
	cout << "*p" << "   " << *p << endl;

	if (p5) 
		cout << "p5不为空" << endl;
	
	else 
		cout << "p5为空" << endl;
	

	std::unique_ptr<int> p6;
	p6.reset(p);
	//p6获取p的使用权 如果p为空 则p6也为空 
	cout << "*p6" << "  " << *p6;
	return 0;

weak_ptr

c++11虽然将weak_ptr指针定为智能指针的一种,但是该类型指针通常不单独使用(没有实际用处)
只能和share_ptr类型指针搭配使用,甚至我们将weak_ptr视为shared_ptr的一个辅助工具
借助weak_ptr指针我们可以获得shared_ptr指针的一些状态信息
比如有多少指向相同的shared_ptr指针,share_ptr指针指向的堆内存是否释放等等

同以上两个智能指针相同 weak_ptr也有很多成员方法


实例



int main() 
	std::shared_ptr<int> p1(new int(10));
	std::shared_ptr<int> p2 = p1;
	std::weak_ptr<int> p3(p2);
	//输出和p3同志向的shared_ptr类型指针的数量
	cout << p3.use_count() << endl;

	p2.reset();//释放

	cout << p3.use_count() << endl;

	cout << *(p3.lock()) << endl;
	//返回一个同指向shared_ptr的指针,获得他存储的数据
	return 0;



以上就是c++11新特性中的三种智能指针

自写智能指针

当我们从对上申请了一个资源的时候,我们就创建一个智能指针对象,它指向这个资源
同时,在对上申请一个其计数作用的资源换,来统计后边所有共享该资源的对象的个数

假如将ptr1的对象赋值给ptr2 那么共享的计数就变为2
如果删除ptr2 引用计数就会减一
删除ptr1,引用计数就会变成0

一旦引用计数变成0 那么释放资源

准备工作:
智能指针对任何类型都可使用,所以他应该是一个模板
其次智能指针是一个类,可以使用构造函数和析构函数对引用计数进行操作
最后他要表现出指针的行为,使用起来像指针一样


template<class T>
class SharedPointer

public:
	//默认构造函数,内部指针,未指向任何资源,引用计数为0,因为它未与任何资源绑定
	SharedPointer() :m_refCount(nullptr), m_pointer(nullptr) 

	//构造函数,初始化时,指向一个已经分配好的资源
	SharedPointer(T* adoptTarget) :m_refCount(nullptr), m_pointer(adoptTarget)
	
		addReference();
	

	//构造函数,使用其它对象创建新对象
	SharedPointer(const SharedPointer<T>& copy)
		:m_refCount(copy.m_refCount), m_pointer(copy.m_pointer)
	
		addReference();
	

	//析构函数,引用计数递减,当为0时,释放资源
	virtual ~SharedPointer()
	
		removeReference();
	

	//赋值操作
	//当左值被赋值时,表明它不再指向所指的资源,故引用计数减一
	//之后,它指向了新的资源,所以对应这个资源的引用计数加一
	SharedPointer<T>& operator=(const SharedPointer<T>& that)
	
		if (this != &that)
		
			removeReference();
			this->m_pointer = that.m_pointer;
			this->m_refCount = that.m_refCount;
			addReference();
		
		return *this;
	

	//判断是否指向同一个资源
	bool operator==(const SharedPointer<T>& other)
	
		return m_pointer == other.m_pointer;
	
	bool operator!=(const SharedPointer<T>& other)
	
		return !operator==(other);
	

	//指针解引用
	T& operator*() const
	
		return *m_pointer;
	
	//调用所知对象的公共成员
	T* operator->() const
	
		return m_pointer;
	

	//获取引用计数个数
	int GetReferenceCount() const
	
		if (m_refCount)
		
			return *m_refCount;
		
		else
		
			return -1;
		
	

protected:
	//当为nullpter时,创建引用计数资源,并初始化为1
	//否则,引用计数加1。
	void addReference()
	
		if (m_refCount)
		
			(*m_refCount)++;
		
		else
		
			m_refCount = new int(0);
			*m_refCount = 1;
		
	

	//引用计数减一,当变为0时,释放所有资源
	void removeReference()
	
		if (m_refCount)
		
			(*m_refCount)--;
			if (*m_refCount == 0)
			
				delete m_refCount;
				delete m_pointer;
				m_refCount = 0;
				m_pointer = 0;
			
		
	

private:
	int* m_refCount;
	T* m_pointer;
;


class MyClass 
private:
	int _id;
public :
	~MyClass()
	
		cout << "释放MyClass(" << _id << ")\\n";
	

	MyClass(int i)
	
		_id = i;
	

	void Print() 
	
		cout << "MyClass(" << _id << ")" << endl;
	

;

int main() 
	MyClass* px = new MyClass(1);

	SharedPointer<MyClass> ap(px);
	SharedPointer<MyClass> bp = ap;
	SharedPointer<MyClass> cp;

	cout << "ap的引用个数:" << ap.GetReferenceCount() << endl;
	cout << "将ap的值赋值给cp" << endl;
	cp = ap;
	cout << "ap的引用计数(3): "<< ap.GetReferenceCount() << endl;
	MyClass* qx = new MyClass(5);
	SharedPointer<MyClass> dp(qx);
	ap = dp;

	cout << "ap的引用计数(2): "
		<< ap.GetReferenceCount() << endl;

	cout << "dp的引用计数(2): "
		<< dp.GetReferenceCount() << endl;

	//"像指针一样使用智能指针"
	dp->Print();
	(*cp).Print();

希望我所写的对大家有帮助

以上是关于c++三种智能指针以及相关知识自写智能指针的主要内容,如果未能解决你的问题,请参考以下文章

智能指针实例

智能指针示例

智能指针

数据结构--智能指针

C++智能指针类模板

智能指针(三十一)