智能指针:C++中优雅的内存管理解决方案

这篇具有很好参考价值的文章主要介绍了智能指针:C++中优雅的内存管理解决方案。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

智能指针:C++中优雅的内存管理解决方案

前言

欢迎来到💖小K💖的💞C++专栏💞,内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况,这是C和C++程序员的噩梦之一。本节将为大家带来解决办法—>智能指针

智能指针:C++中优雅的内存管理解决方案

1、简介

✨智能指针是一个模板类,封装了裸指针,可以对指针进行安全的操作。

  • 使用RAII特点,将对象生命周期使用栈来管理
  • 智能指针区分了所有权,因此使用责任更为清晰
  • 智能指针大量使用操作符重载和函数内联特点,调用成本和裸指针无差别

2、为什么要使用智能指针

✨一句话:智能指针就是帮我们C++程序员管理动态分配的内存的,它会帮助我们自动释放new出来的内存,从而避免内存泄漏!

✨内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况,这是C和C++程序员的噩梦之一。

3、unique_ptr

✨unique_ptr是一种定义在中的智能指针(smart pointer)。它持有对对象的独有权——两个unique_ptr不能指向一个对象,不能进行复制操作只能进行移动操作。

unique_ptr对象是管理的对象的唯一拥有者:因为当unique_ptr对象释放时会删除它们的托管对象,而不考虑其他指针是否仍然指向相同的对象,从而使指向那里的其他指针指向无效的位置。

unique_ptr对象复制了有限的指针功能,通过操作符*和->(用于单个对象)或操作符[](用于数组对象)提供对其托管对象的访问。出于安全考虑,它们不支持指针算术运算,只支持移动赋值(禁用复制赋值)。

✨下面是基本的使用方法

void testOne() 
{
	unique_ptr<int> p(new int(1234));
	cout << *p << endl;
	unique_ptr<int> p1;
	//p1 = p;                     错误,不能赋值和拷贝
	//unique_ptr<int> p2(p);
	p1 = move(p);           //转交所有权
	cout << *p1 << endl;
	//cout << *p << endl;   //错误,p已经失去了管理对象

	unique_ptr<int> p3(new int(897));
	p3.reset(p1.release());
	cout << *p3 << endl;
}

✨需要手动写删除器的情况,一般是操作自定义类型(且注意unique_ptr的删除器写法的,需要手动写入删除器类型)

class MM {
public:
	~MM() {
		cout << "调用析构函数成功" << endl;
	}
};
void testTwo() 
{
	//unique_ptr删除器写法,需要手动写入删除器类型
	unique_ptr<MM,void(*)(MM*&)> Pmm(new MM[4], [](MM*& pmm) {delete[] pmm; });
}

注意当函数参数为unique_ptr类型时,需要使用引用,因为此类型是独享型,禁止拷贝

void print(unique_ptr<int>& p) 
{
	cout << *p << endl;
}

4、shared_ptr

✨unique_ptr是一个独享指针,同一时刻只能有一个unique_ptr指向一个对象,而shared_ptr是一个共享指针,同一时刻可以有多个shared_ptr指向同一对象,但会记录有多少个shared_ptr共同指向一个对象。这便是所谓的引用计数(reference counting)。

✨ 一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动删除。这在非环形数据结构中防止资源泄露很有帮助。

基本用法

void testOne() 
{
	shared_ptr<int> p1; //无参构造
	if (!p1) 
	{
		cout << "空的智能指针对象" << endl;
	}
	shared_ptr<int> p2(new int(1234));
	//shared_ptr<int> p2 = new int(1234); 错误

	shared_ptr<int> p3 = make_shared<int>(1234);  //使用make_shared不支持创建数组
	//怎么访问数据,直接把智能指针对象当做指针来用
	cout << *p3 << endl;
	//cout << p3[0] << endl; 错误,没有下标的使用方式

	//获取管理对象原生指针
	int* k = p3.get();
	cout << *k << endl;
	cout << k[0] << endl;
	//注意:千万不要手动释放原生指针,否则会中断(释放两次)
	//delete k;

	cout << "管理对象数:" << p3.use_count() << endl;
	shared_ptr<int> p4(p3);
	cout << "管理对象数:" << p3.use_count() << endl;

}

vector管理普通指针的弊端

class MM 
{
public:
	MM(string name="",int age=0):name(name),age(age){}
	void print() 
	{
		cout << name << "\t" << age << endl;
	}
	~MM() 
	{
		cout << "调用析构函数" << endl;
	}
protected:
	string name;
	int age;
};
void testTwo() 
{
	cout <<"-----------------------------------" << endl;
	shared_ptr<MM> p(new MM("name1", 19));
	p->print();

	/*****************vector弊端*****************/
	vector<MM*> p1;
	p1.push_back(new MM("name", 20));
	//p1.pop_back();
	p1.clear();
	//可以看到pop和clear函数都不会自动调用析构函数---->当vector操作自定义类型指针的时候
	/*******************************************/

	//比较常用的用法--->工作中
	vector<shared_ptr<MM>> arr;
	shared_ptr<MM> p2(new MM("name"));
	p2->print();
	arr.push_back(p2);
}

上面代码中,当vector管理MM*类型的时候,并不会自动调用析构函数,这时候我们只需要让vector管理shared_ptr就好了

需要手动写删除器的情况,和unique_ptr一样

void testThree() 
{
	cout << "-----------------------------------" << endl;
	shared_ptr<int> king(new int[4] {1, 2, 3, 4});
	int* pNum = king.get();
	for (int i = 0; i < 4; i++)
	{
		cout << pNum[i] << " ";
	}
	cout << endl;

	//当操作特殊类型(自定义类型,c语言文件的打开)的时候,需要手动写删除器
	shared_ptr<MM> p1(new MM[4], [](MM*& pmm) {delete[]pmm; });
	shared_ptr<FILE> pfile(fopen("1.txt", "w+"), [](FILE*& file) {free(file); });
}

✨当shared_ptr当函数参数和返回值的时候,正常写就ok

void pprint(shared_ptr<MM>& mm) {
	mm->print();
}
shared_ptr<int> returnpoint(int num) {
	return shared_ptr<int>(new int(num));
}

5、weak_ptr

shared_ptr可以用来避免内存泄漏,可以自动释放内存。但是在使用中可能存在循环引用,使引用计数失效,从而导致内存泄漏的情况。如下代码所示:

class B;
class A {
public:
	~A() {
		cout << "A" << endl;
	}
	shared_ptr<B> a;
};
class B {
public:
	~B() {
		cout << "B" << endl;
	}
	shared_ptr<A> b;
};
void testOne() 
{
	shared_ptr<A> ao(new A);
	shared_ptr<B> bo(new B);
	ao->a = bo;
	bo->b = ao;
}

我们发现上面的一段代码中,ao中的指针管理bo,bo中的指针管理ao,形成了循环管理,这时候就不会自动释放。这时候我们只需要把shared_ptr改为weak_ptr就ok了

基本处理

weak_ptr只能从shared_ptr或者已有的weak_ptr去构造,不能直接管理对象
不能直接访问管理的对象,访问数据要通过lock()函数去访问shared_ptr,然后再去访问数据文章来源地址https://www.toymoban.com/news/detail-457596.html

void testTwo() 
{
	shared_ptr<int> p(new int(1234));
	cout << "count:" << p.use_count() << endl;
	weak_ptr<int> w(p);
	cout << "count:" << w.use_count() << endl;
	weak_ptr<int> w2(w);
	cout << "count:" << w2.use_count() << endl;
	cout << *w.lock() << endl;
	shared_ptr<int> k = w2.lock();
	cout << *k << endl;
}

到了这里,关于智能指针:C++中优雅的内存管理解决方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 智能资产管理的安全挑战与解决方案

    智能资产管理(Smart Asset Management,SAM)是一种利用人工智能(AI)和大数据技术来优化资产管理过程的方法。它涉及到资产跟踪、资产分析、资产预测和资产优化等方面。随着资产管理的复杂化和数据量的增加,智能资产管理的安全性变得越来越重要。 在智能资产管理中,资产可

    2024年02月22日
    浏览(42)
  • 智能管理护航制造企业安全生产:信息化升级解决方案解析-亿发

    安全生产信息化是通过充分利用信息技术,及时采集安全生产管理中的各种要素和数据,并进行统计分析,随后将分析结果及时反馈,以实现对安全生产管理的指导和帮助,旨在提高安全生产管理的效能。 在提升安全生产管理水平方面,加强安全生产信息化平台建设显得尤为

    2024年01月19日
    浏览(79)
  • Kali 无法联网的解决方案,优雅的配置桥接模式

    打开虚拟网络编辑器: 更改设置: 将VMnet0网卡配置为桥接模式,其中已桥接至应选择你的电脑的网卡(可以通过WIFI属性查看): 编辑虚拟机设置,继续修改网络设备器为桥接模式: 说在前面:有些大学的校园网是无法动态分配多个IP的,所以在实验过程中,还是会出现无法

    2023年04月10日
    浏览(40)
  • vue3+vite2动态绑定图片优雅解决方案

    优雅解决方案在最下面,小伙伴们儿可以直接前往 😊 在vue3+vite2项目中,我们有时候想要动态绑定资源,比如像下面的代码这样: 实际效果是这样: 我们注意到,控制台的报错信息 GET http://127.0.0.1:5173/1.jpg 404 (Not Found) GET :表示向服务器请求资源的方式。 http://127.0.0.1:5173

    2024年02月11日
    浏览(69)
  • Spring Boot 项目优雅关闭(两种完善解决方案附带示例代码)

    Spring Boot 项目优雅关闭常用两种方案,一种是使用 kill -2 和 -15 发送程序终止信号,另一种是使用 spring-boot-actuator 包提供一个优雅下线接口,这两种方案根据自己喜好来,万不得已别用 kill -9 就行,个人推荐第一种,对于Spring Boot 项目来说两种方法只是入口不同,最终关闭逻

    2024年02月03日
    浏览(41)
  • 会议预约管理系统,智慧会议室,智能会议室解决方案,联动会议门牌显示屏,提供会议室的使用效率

    会议室预约管理系统主要用于实现会议室的信息化管理,如在线预约会议室/查看会议室的使用情况,通过会议室门口的电子终端显示屏实时展示当前会议室状态,如会议室现在的使用状态,会议主题,会议预约人,会议时间及该会议室近期的会议情况,预约使用时间等,方便

    2024年02月05日
    浏览(55)
  • SpringBoot Maven 项目打包的艺术--主清单属性缺失与NoClassDefFoundError的优雅解决方案

    这两个问题的出现场景是,你打包完一个SpringBoot、Maven项目,上传Jar包到服务器运行的时候遇到的。也算是比较经典的两个问题了,如果你在打包项目的时候,很容易遇到,这篇文章就是用来一劳永逸地解决它们。 1.1、Jar包运行:没有主清单属性 解决方案 其实这个问题主要

    2024年04月14日
    浏览(30)
  • vue3探索——vue3+vite2动态绑定图片优雅解决方案

    优雅解决方案在最下面,小伙伴们儿可以直接前往 😊 在vue3+vite2项目中,我们有时候想要动态绑定资源,比如像下面的代码这样: 实际效果是这样: 我们注意到,控制台的报错信息 GET http://127.0.0.1:5173/1.jpg 404 (Not Found) GET :表示向服务器请求资源的方式。 http://127.0.0.1:5173

    2024年02月10日
    浏览(57)
  • SpringBoot单元测试报空指针异常解决方案

    java.lang.NullPointerException空指针异常 1.测试类中产生空指针异常,可能不是你的逻辑代码写错了,而是因为获取容器失败,即没有使用正确的测试方法 2.在SpringBoot项目中我们一般可以使用两种Junit进行测试,在导入@Test包时,会出现两个选项 (1)import org.junit.Test; 该junit需要在

    2024年02月11日
    浏览(35)
  • 【前端】内存泄露及解决方案

    内存泄漏是指在程序运行时,分配的内存没有被正确释放,导致内存空间的浪费,最终可能会导致程序崩溃或运行缓慢。 内存泄漏通常是由于程序员在代码中使用不当的内存管理技术或者逻辑错误导致的。例如,程序员可能会忘记释放不再需要的内存块,或者使用了错误的内

    2024年02月16日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包