栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++11 智能指针 知识整理笔记

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++11 智能指针 知识整理笔记

1、智能指针的原理

智能指针是一个类,可以在这个类的构造函数中传入一个普通指针,在析构函数中释放传入的指针。

智能指针主要用于管理在堆上分配的内存,它将普通的指针封装为一个栈对象。当栈对象的生存周期结束后,会在析构函数中释放掉申请的内存,从而防止内存泄漏。

C++里面的四个智能指针: auto_ptr, unique_ptr,shared_ptr, weak_ptr 其中后三个是C++11支持,并且第一个已经被C++11弃用。

用的比较多的是shared_ptr共享指针

2、简单了解一下四种智能指针

按照发展的时间进行展开

2.1 auto_ptr
    auto_ptr以前是用在C98中,C++11被抛弃,头文件一般用来作为独占指针auto_ptr被赋值或者拷贝后,失去对原指针的管理 。auto_ptr不能管理数组指针,因为auto_ptr的内部实现中,析构函数中删除对象使用delete而不是delete[],释放内存的时候仅释放了数组的第一个元素的空间,会造成内存泄漏。auto_ptr不能作为容器对象,因为STL容器中的元素经常要支持拷贝,赋值等操作。

举个栗子,会存在隐藏内存泄露问题,有拷贝语义,拷贝后源对象变得无效,这可能引发很严重的问题。

auto_ptr p1(new int(5));
auto_ptr p2 = p1; // 编译通过,但是后面使用p1会出现内存泄漏问题
2.2 unique_ptr:
    C++11中用来替代auto_ptr拷贝构造和赋值运算符被禁用,不能进行拷贝构造和赋值运算虽然禁用了拷贝构造和赋值运算符,但unique_ptr可以作为返回值,用于从某个函数中返回动态申请内存的所有权,本质上是移动拷贝,就是使用std:move()函数,将所有权转移。
unique_ptr p1(new int(5));
unique_ptr p2 = p1; // 编译会出错
unique_ptr p3 = std::move(p1); // 转移所有权, 现在那块内存归p3
2.3 share_ptr:​​ ​​ ​​

目前使用得比较多的智能指针,要熟悉其原理

    多个指针可以指向相同的对象,调用release()计数-1,计数0时资源释放use_count()查计数;reset()放弃内部所有权;share_ptr多次引用同一数据会导致内存多次释放 ;循环引用会导致死锁;引用计数不是原子操作。
2.3.1手写智能指针类需要实现哪些函数?以及注意哪些细节
    采用模板函数区设计,私有成员为指针以及指针技术;带参的构造函数中负责引用计数的自增;析构函数负责引用计数的减1和释放内存;定义拷贝构造函数和赋值函数以及移动函数
2.3.2简单版的实现方法
#include
using namespace std;

template
class SharedPtr
{
private:
	T* _ptr;
	int* _pcount;// 指向引用计数的指针 
	
public:
	SharedPtr(T* ptr = nullptr):_ptr(ptr), _pcount(new int(1))
	{}
	
	SharedPtr(const SharedPtr& s):_ptr(s._ptr), _pcount(s._pcount){
		(*_pcount)++;
	}
	
	// 赋值构造函数
	SharedPtr& operator=(const SharedPtr& s){
		if(this != &s)
		{
			if(--(*(this->_pcount)) == 0)
			{
				delete this->_ptr;
				delete this->_pcount;
			}
			_ptr = s._ptr;
			_pcount = s._pcount;
			*(_pcount)++;
		}
		return *this;
	} 
	
	T& operator*()
	{
		return *(this->ptr);
	}
	T* operator->()
	{
		return this->ptr;
	}
	~SharedPtr()
	{
		--(*(this->_pcount ));
		if(*(this->_pcount == 0)){
			delete _ptr;
			_ptr = nullptr;
			delete _pcount;
			_pcount = nullptr;
		}
	}		
};

int main(){
	int b = 20;
	int *p = &b;
	SharedPtr* sharep = new SharedPtr(p);
}

但是shree_ptr还是无法解决一些问题:

2.3.3 智能指针的循环使用

循环引用是指使用多个智能指针share_ptr时,出现了指针之间相互指向,从而形成环的情况,有点类似于死锁的情况,这种情况下,智能指针往往不能正常调用对象的析构函数,从而造成内存泄漏。

//智能指针的循环使用
#include
#include
using namespace std;

template
class Node
{
public:
	Node(const T& value):_pPre(NULL),_pNext(NULL),_value(value){
		cout<<"Node()"<>_pPre;
	shared_ptr> _pNext;
	T _value;
};

void Funtest()
{
	shared_ptr> sp1(new Node(1));
	shared_ptr> sp2(new Node(2));
	
	cout << "sp1.use_count:" << sp1.use_count() << endl;
	cout << "sp2.use_count:" << sp2.use_count() << endl;
	
	sp1->_pNext =sp2;//sp1的引用+1
	sp2->_pPre = sp1;//sp2的引用+1
	
	cout<< "sp1.use_count: "<< sp1.use_count() < 


只有当sp1的计数为0时才析构,而上述情况造成了一个僵局,那就是当析构sp2时候,由于sp2->pre = sp1,sp1还在用,而sp1又会用sp2,所以sp2.use_count减减之后为1,不释放,sp1也是相同的道理,由于sp1的空间sp2还在使用中,所以sp1.use_count减减之后为1,也不释放。sp1等着sp2先释放,sp2等着sp1先释放,二者互不相让,导致最终都没能释放,内存泄漏。

在实际编程过程中,应该尽量避免出现智能指针之前相互指向的情况,如果不可避免,可以使用使用弱指针——weak_ptr,它不增加引用计数,只要出了作用域就会自动析构。

为了解决上述存在的问题,需要引入弱智能指针

4.weak_ptr

1.解决两个share_ptr互相引用产生死锁,计数永远降不到0,没办法进行资源释放,造成内存泄漏的问题。

2.使用时配合share_ptr使用,把其中一个share_ptr更换为weak_ptr。

weak_ptr用于避免shared_ptr相互指向产生的环形结构,造成的内存泄漏。weak_ptr count是弱引用个数;弱引用个数不影响shared count和对象本身,shared count为0时则直接销毁。

3 参考学习资料:
    阿秀笔记C++智能指针C++智能指针-博客园牛客网智能指针笔记

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/767220.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号