智能指针share_ptr,unique_ptr,weak_ptr。再也不要担心内存管理的问题了

本文详细探讨了C++中智能指针的概念,包括共享智能指针(share_ptr)、独占智能指针(unique_ptr)和弱智能指针(weak_ptr)的工作原理与使用场景。通过实例演示了智能指针如何自动管理内存,减少内存泄漏风险。

share_ptr

共享智能指针,从名字就能知道,它是一个共享的指针,也就说开辟一块堆空间,大家一起共用。
在这里插入图片描述
那我们怎么去管理这片共有的内存呢?share_ptr是一个模板类,在它里面有个成员count,专门用来记录有多少个指针同时指向了这份内存,如果有一个对象发生了析构,但是count值不为0表明还有其他对象在使用这一片内存,就不需要释放这块内存。所以这种指针一般用于多个类对象共享一块内存。
下面从debug模式观察一下整个在内存上的存储情况
在这里插入图片描述
下面给出一个特别注意的地方,如果用一个指针去初始化智能指针,这个智能指针发生析构时只是释放这个指针,并不会释放指针指向的内容。如下debug看到的情况(如果有错误欢迎指出)
在这里插入图片描述
当debug到22行时可以观察到pv地址下内存已经初始化。
在这里插入图片描述
在25行的时候明细观察到智能指针指向了pv这个地址
在这里插入图片描述
在这里插入图片描述
当执行到29行时,已经出了智能指针的作用域,我们发现pv指针指向的内容并没有被释放。但是智能指针指向的指针已经被释放。
在这里插入图片描述
执行完delete后所有内存才释放完毕。所以,如果有这样的使用情况还是值得注意的。

share_ptr相关的一些验证。

至于有关share_ptr的一些特性,可以参考C++primer,这里给出一些有趣的验证而已。
1.验证share_ptr指向同一份地址空间,当发生拷贝构造时count会增加。

shared_ptr<string> p(new string);
	p->append("abc");
	p->append("bcd");
	
	cout << (*p)[1] << endl;
	//这里使用P.xx访问成员方法时,p是作为一个对象存在的,而此时的p是存放在栈上的,而*p是将p解引用的结果,就是指针的基本用法
	cout << p.use_count() << endl;//1
	auto p2(p);//拷贝构造,数量加一;
	cout << p2.use_count() << endl;//2
	(*p)[0] = 'd';//由于share_ptr是指向同一份内存地址的,所以一个指针改变其中的内容,其余也会跟着改变,可以用在多对象共享数据
	cout << *p << endl;
	cout << *p2 << endl;
	cout << hex << p << endl;//查看指针指向的地址
	cout << hex << p2 << endl;//查看指针指向的地址

对应的输出
在这里插入图片描述
可以观察到实际的输出结果和预想的是一样的,两个只能指针都指向了014AC830这个地址。
2.验证智能指针的智能指针
我们知道指针有多级指针,不知道智能指针是否有这个呢?

shared_ptr<string> p3;
	//如果一个智能指针是一个指向智能指针的指针呢?
	{
		//让q的作用域仅限于大括号内,观察p3是否会被释放
		shared_ptr<shared_ptr<string>> q(new shared_ptr<string>(new string));
		cout << q->use_count() << endl;//1
		(*q)->append("abcdef");
		cout << (**q) << endl;//输出abcdef
		cout <<hex<<*q << endl;
		p3 =(*q);//拷贝构造
		cout << (*p3) << endl;
		cout << "---------------修改后内容------------------" << endl;
		(**q)[0] = 'g';
		cout << (*p3) << endl;//gbcdef
		cout << (**q) << endl;//gbcdef
		cout << q->use_count() << endl; //2
	}//出了括号shared_ptr<shared_ptr<string>> q析构,从而释放shared_ptr<string>,然后shared_ptr<string>自己再析构,使得count--
	cout << (*p3) << endl;
	cout << hex << p3 << endl;
	cout << p3.use_count() << endl;//1

在这里插入图片描述
可以观察到二级指针也是完全没问题的,同样解引用得到的地址和一级指针是一致的。
3.指向函数的智能指针


int add(int a, int b) {
	return a + b;
}
typedef int(*myadd)(int, int);

//指向函数的智能指针
//myadd 是一个函数指针,用add这个函数初始化myadd这个函数指针
shared_ptr<myadd> pfunc(new myadd(add));
cout << (*pfunc)(1, 2) << endl;

事实和普通的函数指针用法是一致的。

有关share_ptr的一些小结

share_ptr通过count这个值记录指针引用的个数,从而决定什么时候完全释放指针指向的对象。减少了我们对内存管理的要求,假设我们申请了某个堆对象的时候,但是我们却不是很清楚什么时候该释放它,这个时候智能指针就很有用了。

unique_ptr

uinque_ptr是一个独占式的指针,也就是说同一时刻只有一个指针能指向这个对象,如果其他的指针想进入就必须先释放之前的然后再由新的指针指向该段内容。为了实现这个效果,unique_ptr是不提供直接的拷贝构造方法,必须先release()一个当前指针,但是在release的时候必须由另一个指针接受,要不然指针被释放了,指向的内存空间没被释放会造成内存泄漏的问题。

unique_ptr<string> p1(new string("text"));
	
	unique_ptr<string> p2(p1.release());
	//cout << (*p1) << endl; //p1的指针已经被释放了
	//unique_ptr<string> p2(p1);//错误,不可以直接拷贝
	//p2.release();//不可以直接删除P2这样一来失去控制权无法析构内存
	auto p3 = p2.release();

在这里插入图片描述

weak_ptr

weak_ptr是一种不控制对象生存周期的智能指针,它指向一个有share_ptr管理的对象,当使用share_ptr初始化weak_ptr的时候share_ptr的count值不会增加,当share_ptr完全被析构的时候,weak_ptr也就相对应的失效了。所以weak_ptr是一种弱类型的指针,它不可以直接使用,必须使用lock方法返回一个share_ptr再去访问对象。

	auto q = make_shared<string>(10, '9');
	weak_ptr<string> pw(q);
	//cout << *pw << endl; //错误,不能直接访问
	//pw->push_back('a');//错误,不能直接访问
	auto p = pw.lock();
	p->push_back('a');
	if (p) {
		cout << *p << endl;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值