智能指针的原理及其应用

Posted

tags:

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

所谓智能指针就是自动化管理指针所指向的动态资源的释放。

那么智能指针的引用是为了解决哪些问题呢?

代码中经常会忘掉释放动态开辟的资源,引用智能指针可用于动态资源管理,资源分配即初始化,定义一个类来封装资源的分配和释放,在构造函数中完成资源的分配和初始化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放。

智能指针的原理:智能指针是一个类,这个类的构造函数中传入一个普通指针,析构函数中释放传入的指针。智能指针的类是栈上的对象,智能指针指向堆上开辟的空间,函数结束时,栈上的函数会自动被释放,智能指针指向的内存也会随之消失,防止内存泄漏。

智能指针的实现需要实现构造、析构、拷贝构造、操作符重载。

几种常见的智能指针的区别?

auto_ptr:就是内部使用一个成员变量指向一块内存资源(构造函数),并且在析构函数中释放内存资源。auto_ptr的拷贝构造和赋值操作符重载函数所接受的参数都是非const的引用类型(即我们可以且修改资源),不能共享所有权(其它任意一个指针指向这块内存,它会把内存给别的指针,自己不指向了)。权限转移。

template <typename T>
class Auto_Ptr
{
public:
	Auto_Ptr(T *ptr = NULL)
		:_ptr(ptr)
	{}
	~Auto_Ptr()
	{
		if (_ptr != NULL)
		{
			delete _ptr;
			cout<<"~Auto_Ptr()"<<endl;
		}
	}
	Auto_Ptr(Auto_Ptr<T> &ap)
		:_ptr(ap._ptr)
	{
		ap._ptr = NULL;
	}
	Auto_Ptr<T> &operator= (Auto_Ptr<T> &ap)
	{
		if (this != &ap)
		{
			delete _ptr;
			_ptr = ap._ptr;
			ap._ptr = NULL;
		}
		return *this;
	}
private:
	T *_ptr;
};

void Test1()
{
	Auto_Ptr<int> a1(new int(1));
	Auto_Ptr<int> a2(a1);
	Auto_Ptr<int> a3(new int(2));
	a1 = a1;
	a2 = a3;
}

scoped_ptr有着与auto_ptr类似的特性,scoped_ptr与auto_ptr最大的区别主要在于对内存资源拥有权的处理。(auto_ptr在拷贝构造时会从源auto_ptr自动交出拥有权,而scoped_ptr则不允许被拷贝)。scoped_ptr不能资源共享。

template <typename T>
class Scoped_Ptr
{
public:
	Scoped_Ptr(T *ptr)
		:_ptr(ptr)
	{}
	~Scoped_Ptr()
	{
		if (_ptr != NULL)
		{
			delete _ptr;
			cout<<"~Scoped_Ptr()"<<endl;
		}
	}

private:
	Scoped_Ptr(const Scoped_Ptr<T> &sp);
	Scoped_Ptr<T> &operator=(const Scoped_Ptr<T> &sp);
	T *_ptr;
};

void Test2()
{
	Scoped_Ptr<int> s1(new int(1));
	//Scoped_Ptr<int> s2(s1);
	Scoped_Ptr<int> s3(new int(2));
	//s1 = s1;
	//s2 = s3;
}

shared_ptr就是为了解决auto_ptr在对象所有权上的局限性,在使用引用计数的基础上提供了可以共享所有权的智能指针。当新增一个shared_ptr对该对象进行管理时,就将该对象的引用计数加一,同理减少一个时,计数器减一。当该对象的引用计数器为0时,调用delete释放其所占的内存。

template <typename T>
class Shared_Ptr
{
public:
	Shared_Ptr(T *ptr)
		:_ptr(ptr)
		,_count(new int(1))
	{}
	~Shared_Ptr()
	{
		if(--(*_count) == 0)
		{
			delete _ptr;
			delete _count;
			cout<<"~Shared_Ptr()"<<endl;
		}
		(*_count)--;
	}
	Shared_Ptr(Shared_Ptr<T> &sp)
		:_ptr(sp._ptr)
		,_count(sp._count)
	{
		(*_count)++;
	}
	Shared_Ptr<T> &operator=(Shared_Ptr<T> &sp)
	{
		if (this != &sp)
		{
			if (--(*_count) == 0)
			{
				delete _ptr;
				delete _count;
			}
			_ptr = sp._ptr;
			_count = sp._count;
			(*_count)++;
		}
		return *this;
	}
private:
	T *_ptr;
	int *_count;
};

void Test3()
{
	Shared_Ptr<int> s1(new int(1));
	Shared_Ptr<int> s2(s1);
	Shared_Ptr<int> s3(new int(2));
	s1 = s1;
	s1 = s3;
}

shared_ptr存在循环引用的问题,使用weak_ptr可以用来避免循环引用。但是weak_ptr对象引用资源时不会增加引用计数,无法知道资源会不会被突然释放,所以无法通过weak_ptr访问资源。在访问资源时weak_ptr必须先转化为shared_ptr。

#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
using namespace std;
using namespace boost;
struct ListNode
{
	shared_ptr<ListNode > _prev;
	shared_ptr<ListNode > _next;
	//weak_ptr<ListNode > _prev;
	//weak_ptr<ListNode > _next;
	~ ListNode()
	{
		cout<<"~ListNode()" <<endl;
	}
};
void Test ()
{
// 循环引用问题
	shared_ptr <ListNode > p1( new ListNode ());
	shared_ptr <ListNode > p2( new ListNode ());
	cout <<"p1->Count:" << p1. use_count()<<endl ;
	cout <<"p2->Count:" << p2. use_count()<<endl ;
	// p1节点的_next指向 p2节点
	p1->_next = p2;
	// p2节点的_prev指向 p1节点
	p2->_prev = p1;
	cout <<"p1->Count:" << p1. use_count ()<<endl ;
	cout <<"p2->Count:" << p2. use_count ()<<endl ;
}


以上是关于智能指针的原理及其应用的主要内容,如果未能解决你的问题,请参考以下文章

Android系统的智能指针(轻量级指针强指针和弱指针)的实现原理分析

Qt智能指针

智能指针的原理和简单实现

C++ - 指针和“智能指针”

图解shared_ptr共享智能指针原理分析

使用 Kotlin 在片段中引用 RecyclerView 时出现空指针错误