C++重新认知:智能指针

0/# 一、为什么要有智能指针
内存泄露是我们开发大型项目时最为头疼的问题,当我们将对象建立在堆上时,因为需要我们自己手动释放,因此避免不了忘记删除,或者删除时没有考虑清楚情况的问题,从而造成悬挂指针或者是野指针的问题。

二、智能指针是什么

简单理解的话,智能指针采用RAII机制。即虽然智能指针虽然是以指针的方式运作,但是实际上是一个对象,在自己生命周期结束后,会自动释放掉,这样的话就不用让开发人员时刻把心思放在释放对象这个问题上了,也降低了内存泄漏的概率。

在C++中,智能指针一共定义了4种:
auto_ptr、unique_ptr、shared_ptr 和 weak_ptr。 其中,auto_ptr在C++11种已经摒弃掉,在C++17中已经废除不可用。

三、智能指针

1、unique_ptr

在这里插入图片描述
指针p在运行完test()函数后会直接释放掉。
在这里插入图片描述
需要注意的是,unique_ptr并没有负责复制的构造函数,因此不支持拷贝和赋值操作。原因是unique_ptr会独享p1的所有权,如果p2和p3失去p1的所有权时(即p1释放掉)会delete p1两次,p1释放一次,p2释放会再次delete p1一次。
在这里插入图片描述
虽然不能够拷贝和赋值操作,但是可以将p1的所有权转移给p2管理,使用std::move函数即可。

unique最常见的使用场景,就是替代原始指针,为动态申请的资源提供异常安全保证。

#include<iostream>
#include<vector>
using namespace std;class Test
{
public:void add();
};
void Test::add()
{;
}int main()
{//情况一Test* t = new Test();t->add();delete t;//情况二unique_ptr<Test> t(new Test);t->add();delete t;
}

在这个场景中,如果情况一中 t 执行add()函数,执行过程中出现异常,导致无法执行后面无法释放掉对象。
而情况二中,即使 t 执行add()函数出现异常,无法继续后面delete t 代码时,但对象 t 生命周期结束后,智能指针会自动调用析构函数,释放掉对象。

2、shared_ptr

大部分提到的智能指针很大概率上指的是shared_ptr,它采用的机制是引用计数,即实现对一块内存的多个引用,在最后一个引用被释放时,指向的内存才释放。shared_ptr可以进行赋值和拷贝操作。
shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用他一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,删除所指向的堆内存。
在这里插入图片描述
获取原始指针:在这里插入图片描述

注意事项:

  • 不能将一个原始指针初始化多个shared_ptr对象(因为会多次删除相同指针)
    在这里插入图片描述
  • 循环引用问题
#include<iostream>
#include<vector>
using namespace std;
struct Father
{shared_ptr<Son> son_;
};struct Son
{shared_ptr<Father> father_;
};int main()
{father = make_shared<Father>();auto son = make_shared<Son>();father->son_ = son;son->father_ = father;return 0;
}

该部分代码会有内存泄漏问题。原因是
1.main 函数退出之前,Father 和 Son 对象的引用计数都是 2。
2.son 指针销毁,这时 Son 对象的引用计数是 1。
3.father 指针销毁,这时 Father 对象的引用计数是 1。
4.由于 Father 对象和 Son 对象的引用计数都是 1,这两个对象都不会被销毁,从而发生内存泄露。

为避免循环引用导致的内存泄露,就需要使用 weak_ptr。weak_ptr 并不拥有其指向的对象,也就是说,让 weak_ptr 指向 shared_ptr 所指向对象,对象的引用计数并不会增加。
使用 weak_ptr 就能解决前面提到的循环引用的问题,方法很简单,只要让 Son 或者 Father 包含的 shared_ptr 改成 weak_ptr 就可以了。

#include<iostream>
#include<vector>
using namespace std;struct Father
{shared_ptr<Son> son_;
};struct Son
{weak_ptr<Father> father_;
};int main()
{shared_ptr<Father> father = make_shared<Father>();shared_ptr<Son> son = make_shared<Son>();father->son_ = son;son->father_ = father;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/473876.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Sora技术报告——Video generation models as world simulators

文章目录 1. 视频生成模型&#xff0c;可以视为一个世界模拟器2. 技术内容2.1 将可视数据转换成patches2.2 视频压缩网络2.3 Spacetime Latent Patches2.4 Scaling transformers 用于视频生成2.5 可变的持续时间&#xff0c;分辨率&#xff0c;宽高比2.6 抽样的灵活性2.7 改进框…

【Linux】Framebuffer 应用

# 前置知识 LCD 操作原理 在 Linux 系统中通过 Framebuffer 驱动程序来控制 LCD。 Frame 是帧的意思&#xff0c; buffer 是缓冲的意思&#xff0c;这意味着 Framebuffer 就是一块内存&#xff0c;里面保存着一帧图像。 Framebuffer 中保存着一帧图像的每一个像素颜色值&…

4核8G服务器支持多少人同时在线访问?

腾讯云4核8G服务器支持多少人在线访问&#xff1f;支持25人同时访问。实际上程序效率不同支持人数在线人数不同&#xff0c;公网带宽也是影响4核8G服务器并发数的一大因素&#xff0c;假设公网带宽太小&#xff0c;流量直接卡在入口&#xff0c;4核8G配置的CPU内存也会造成计算…

Unity类银河恶魔城学习记录7-7 P73 Setting sword type源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili Sword_Skill_Controller.cs using System.Collections; using System.Col…

基于SringBoot+Vue的大学生社团管理系统

末尾获取源码作者介绍&#xff1a;大家好&#xff0c;我是墨韵&#xff0c;本人4年开发经验&#xff0c;专注定制项目开发 更多项目&#xff1a;CSDN主页YAML墨韵 学如逆水行舟&#xff0c;不进则退。学习如赶路&#xff0c;不能慢一步。 目录 一、项目简介 1.1 研究背景 1.…

C语言之日历问题

一、代码展示 #include<stdio.h> int leapyear(int year)//判断是不是闰年函数 {if (year % 4 0 && year % 100 ! 0 || year % 400 0)return 1;elsereturn 0; } int days(int year, int month, int* day)//判断一个月有几天 {if (month ! 2)return day[month…

如何在JavaScript中使用大于和小于运算符

在你的 JavaScript 程序中&#xff0c;你经常需要比较两个值&#xff0c;以确定一个是否大于另一个或小于另一个。这就是大于和小于运算符派上用场的地方。 在本文中&#xff0c;我们将通过代码示例更详细地介绍如何使用这些运算符。 &#xff08;本文内容参考&#xff1a;ja…

Acwing---875. 快速幂

快速幂 1.题目2.基本思想3.代码实现 1.题目 给定 n n n 组 a i ai ai, b i bi bi, p i pi pi&#xff0c;对于每组数据&#xff0c;求出 abii m o d mod mod pi 的值。 输入格式 第一行包含整数 n n n。 接下来 n n n 行&#xff0c;每行包含三个整数 a i ai ai, b i …

Leetcode-102. 二叉树的层序遍历

今天的情人节和树过了...... 题目&#xff1a; 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[…

【机器学习笔记】 9 集成学习

集成学习方法概述 Bagging 从训练集中进行子抽样组成每个基模型所需要的子训练集&#xff0c;对所有基模型预测的结果进行综合产生最终的预测结果&#xff1a; 假设一个班级每个人的成绩都不太好&#xff0c;每个人单独做的考卷分数都不高&#xff0c;但每个人都把自己会做的…

Atmel ATSHA204应用总结

1 ACES软件安装 Atmel Crypto Evaluation Studio (ACES) https://www.microchip.com/DevelopmentTools/ProductDetails/PartNO/Atmel%20Crypto%20%20Studio%20(ACES) 2 基本概念 ACES CE&#xff1a;Atmel Crypto Evalution Studio Configuration Environment&#xff08;基于加…

L2-021 点赞狂魔

一、题目 二、解题思路 统计每个人点赞的不同标签的数量&#xff1a;每行列出一位用户的点赞标签&#xff0c;这些标签可能有重复的&#xff0c;所以将用户的点赞标签存放在 set 里&#xff0c;通过 size() 函数获得点赞的不同标签的数量&#xff1b;结构体包括用户的信息&…