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

c++三种智能指针shared

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

c++三种智能指针shared

c++智能指针总结 一、智能指针出现的原因

1. 基于我们的的编程习惯,在堆区动态管理的资源忘记释放或者回收了,导致内存泄漏。
2. 有多个指针指向同一片内存的问题,造成内存资源的重复释放或回收。
3. 程序在在抛出异常前申请了资源,以至于异常抛出时导致程序中断,无法执行析构函数delete内存从而导致的内存泄漏。

基于上面三个主要的原因,聪明的程序员就提出了智能指针方便管理我们自己的内存,一定程度上解决了c++为了人所诟病的内存管理问题。
注意:三种指针包含在头文件< memory >.

二、智能指针的本质及其原理
  • 智能指针的本质一个对象,是一个行为表现都像指针的对象。它的封装利用了RAII机制或者思想,其RAII机制或者思想是“资源获取就是初始化”,是C++语言的一种管理资源、避免泄漏的惯用法。
  • 智能指针可分为两部分,一个是原指针,一个是引用计数(关联的计数器)。创建一个智能指针的时候引用计数为1,当引用计数为0的时候,智能指针本身会自动释放。当该智能指针被其他指针所用,引用计数就会相应的叠加,可以这么理解:引用计数的大小就是当前管理该内存的指针的数量。
三、三种智能指针的介绍 1.shared_ptr

1.初始化和赋值(注意不要用一个原始指针初始化多个shared_ptr 会导致重复释放内存)

#include 
#include
int main() {
	int* a = new int(10);
	std::shared_ptrs1(a);
	std::shared_ptrs2(new int(10));
	std::shared_ptrs3 = s1;
	std::shared_ptrs4=make_shared(30);
	auto s5 = std::make_shared(20);	
	return 0;
}

2.重载原始指针的“*”和“->”

#include 
#include
class Person
{
public:
	Person(int a) :a(a){}
public:
	int a;
};
int main() {
	std::shared_ptrs(new Person(2));
	//与原始指针的使用方式一样
	std::cout << (*s).a << std::endl;
	std::cout << s->a << std::endl;
		return 0;
}

3.其他成员函数的作用和使用

#include 
#include
#include
class Person
{
public:
	Person(int a) :a(a){}
public:
	int a;
};
int main() {
	std::shared_ptrs(new Person(2));
	std::cout << (*s).a << std::endl;
	std::cout << s->a << std::endl;

	std::cout << s.use_count() << std::endl;//得到引用计数的数量即当前管理该内存的指针的个数
	Person*p = s.get();//得到原始的指针

	std::shared_ptrs2 = s;
	std::cout << s.use_count() << std::endl;
	s.~shared_ptr();//析构函数它的作用是use_count()--然后其检查是否为0 若为0就释放,若不为0选择无视
	std::cout << s2.use_count() << std::endl;//此处打印为1说明上面析构函数没有释放内存资源
	
	std::shared_ptrs3(new Person(4));
	s3.swap(s2);//交换管理的内存,交换指针
	swap(s2, s3);//跟上面效果一样

	if (s2.unique())std::cout << "资源是被唯一管理的" << std::endl; //用来判断资源是否是被唯一管理的

	s2.reset();//强制释放资源,将s2的use_count()置为0 指针指向nullptr
	s3.reset(new Person(10));//重置资源
	std::cout<< s3->a<< std::endl;

	return 0;
}
2.weak_ptr

关于弱指针,我们先要追究一下它的来由,看下面代码:

#include 
#include
class Son;
class Father;
using fatherptr = std::shared_ptr;
using sonptr = std::shared_ptr;
class Father
{
public:
	sonptr s;
	Father();
	~Father();
};
class Son
{
public:
	fatherptr f;
	Son();
	~Son();
};

Father::Father() { std::cout << "hello father"< std::cout << "bye father"< std::cout << "hellow son"< std::cout << "bye son" << std::endl; }

using fatherptr = std::shared_ptr;
using sonptr = std::shared_ptr;
int main() {

	fatherptr f(new Father());
	sonptr s(new Son());
    f->s = s;
    s->f = f;  //循环调用

	std::cout << f.use_count() << std::endl;//输出2
	std::cout << s.use_count() << std::endl;//输出2

    return 0;
}

有如下结果:

发现它并没有调用智能指针指向的对象的析构函数!!为啥呢??
原因是:在智能指针调用析构函数的时候先将use_count- -当use_count等于0的时候,释放所指对象的内存资源,但是这里它发现use_count等于1,相当于给它传递一个信息,还有指针在用这一片资源,不能释放!从而导致了这里内存的泄露,这也是share_ptr在这种循环调用中的缺陷!!

那么怎么解决,聪明的程序员就开发出了weak_ptr,可以这么说,weak_ptr就是为了协助share_ptr而生。它本身不具备指针的功能没有重载的“*”和“->”.
它的成员函数都是为了监测shared_ptr所管理的资源而设计的。

#include 
#include
class Person
{
public:
	Person(int a) :a(a) {}
public:
	int a;
};
int main() {
	std::shared_ptrs(new Person(2));
	std::weak_ptrw = s;
	std::weak_ptrw2(s);
	std::weak_ptrw3(w2);   //weak_ptr从一个shared_ptr或者weak_ptr进行对象构造的初始化

	std::cout << s.use_count() << std::endl;//输出为1,说明weak_ptr构造它的时候引用计数不会增加
	                                        //weak_ptr没有参与资源管理,只是对资源的监控
	std::cout << w2.use_count() << std::endl;

	auto s2 = w.lock();//返回一个指向该资源的shared_ptr
	
	if(w.expired())//判读weak_ptr监控的shared_ptr是不是空资源 相当于use_cout==0,但是这种方式更快
	{std::cout<<"shared_ptr指向的是空区域"<std::cout<<"shared_ptr管理的资源不是空" ;}
	
	return 0;
}

那等于循环调用 我们如何通过弱指针来解决呢?

#include 
#include
#include

class Son;
class Father;
using fatherptr = std::shared_ptr;
using sonweakptr = std::weak_ptr;
using sonptr = std::shared_ptr;
class Father
{
public:
	sonweakptr s;
	Father();
	~Father();
};
class Son
{
public:
	fatherptr f;
	Son();
	~Son();
};

Father::Father() { std::cout << "hello father"< std::cout << "bye father"< std::cout << "hellow son"< std::cout << "bye son" << std::endl; }

int main() {

	fatherptr f(new Father());
	sonptr s(new Son());
    f->s = s;
    s->f = f;  //循环调用

	std::cout << f.use_count() << std::endl;
	std::cout << s.use_count() << std::endl;

    return 0;
}

我们把其中一个成员指针改成弱指针,就有如下结果:

这样就解决了shared_ptr循环调用的问题。

3.unique_ptr

unique顾名思义,唯一的指向一个对象,该对象不能被共享(指针和资源一对一),unique_ptr向比于原始指针,使得在出现异常的情况下动态资源得以释放,unique_ptr的释放规则是:unique_ptr从指针开始,到离开作用域时,释放其指向的对象资源。
unique_ptr用法:

#include
#include
int main()
{
	std::unique_ptr u(new int(10));//绑定申请的堆区资源
	std::unique_ptru2(std::move(u));//转移所有权到u2(移动语义) 
	
	//std::unique_ptru2(u);不能拷贝
	//std::unique_ptru3=u;不能赋值

	u.release();//释放所有权
	u.reset(new int(20));//重新制定所有权

}

其余操作和shared_ptr类似。

总结

智能指针能给我们资源管理带来极大的便捷,但是凡是都有两面性,智能指针所带来的便捷,其实是由性能消耗换来的,在追求极致性能的时候,不要盲目使用智能指针。

写了一个下午,给菜鸡一个鼓励一下吧~~

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

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

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