了解常用智能指针

智能指针

1、概念

C++中引入智能指针的主要目的是为了解决内存管理的问题,传统的指针(裸指针)在使用时需要手动分配和释放内存,容易出现内存泄漏悬挂指针等问题。智能指针通过封装裸指针,并提供自动内存管理功能,使得内存资源可以更安全、高效地管理。

2、内存泄漏

有人说,我每次记得将new过的指针delete,是不是就可以不使用智能指针了呢?智能指针怪麻烦的!但有些时候指针不是你想delete他就真的delete了

我举个例子:

#include <iostream>
#include <string>
#include <memory>

using namespace std;


// 1、动态分配内存,没有释放就return
void memoryLeak1() {
	string *str = new string("动态分配内存!");
	return;
}

// 2、动态分配内存,虽然有些释放内存的代码,但是被半路截胡return了
int memoryLeak2() {
	string *str = new string("内存泄露!");

	// ...此处省略一万行代码

	// 发生某些异常,需要结束函数
	if (1) {
		return -1;
	}
	// 另外,使用try、catch结束函数,也会造成内存泄漏!
	

	delete str;	// 虽然写了释放内存的代码,但是遭到函数中段返回,使得指针没有得到释放
	return 1;
}


int main(void) {

	memoryLeak1();

	memoryLeak2();

	return 0;
} 

对于第二种内存泄漏,在代码中发现异常需要结束函数,后面的delete并没有执行,此时指针并没有释放,即会导致内存泄漏。

3、智能指针原理

智能指针本质是一个类模板它可以创建任意的类型的指针对象,当智能指针对象使用完后,对象就会自动调用析构函数去释放该指针所指向的空间。如下所示:

在这里插入图片描述

这样即可自己写一个简易的智能指针:

#pragma once
#include <iostream>
template<class T>
class smartptr
{
public:
	smartptr(T* ptr = nullptr)
		:_ptr(ptr)
	{};
	~smartptr()
	{
		std::cout << "ptr delete..." << std::endl;
		if (_ptr)
			delete _ptr;

	}

private:
	T* _ptr;
};

测试:

#include "smartpoint.h"
void test1() 
{
	smartptr<int> ptr1;
	smartptr<double> ptr2;
	smartptr<bool> ptr3;
}

int main()
{
	test1();
	return 0;
}

结果:
在这里插入图片描述

4、常见智能指针

1、auto_ptr

std::auto_ptr是C++98标准中提供的智能指针,它是独占式智能指针,已经过时,在这里不深究

2、unique_ptr

std::unique_ptr是C++11标准引入的智能指针,其核心思想是独占所有权(exclusive ownership)和资源管理的责任。

核心思想(禁止拷贝和可以Move):

  • 独占所有权:std::unique_ptr独占所管理的指针资源,同一时间只能有一个std::unique_ptr拥有该资源。当std::unique_ptr被销毁或转移所有权时,它会自动释放所管理的资源,确保资源在适当的时候被正确释放,避免资源泄漏。
  • 确保资源的释放:std::unique_ptr通过在析构函数中自动调用delete来释放所管理的资源。这意味着,无论是通过正常的控制流还是异常的控制流,只要std::unique_ptr被销毁,资源都会得到释放,避免了手动释放资源的繁琐和可能的遗漏。
  • 禁止拷贝:std::unique_ptr禁止拷贝构造函数和拷贝赋值运算符的使用,以确保同一时间只有一个std::unique_ptr拥有资源的所有权。这样可以防止多个智能指针同时管理同一块资源,避免了资源的重复释放和悬挂指针的问题。
  • 支持移动Move语义:std::unique_ptr支持移动构造函数和移动赋值运算符,允许资源的所有权从一个std::unique_ptr对象转移到另一个对象,避免了资源的不必要拷贝。

unique_ptr创建:

int main()
{
	{
	// std::unique_ptr<Entity> entity = new Entity(); // 错误
	// std::unique_ptr<Entity> entity(new Entity()); // 普通指针使用方法
		std::unique_ptr<Entity> entity = std::make_unique<Entity>(); // 最好使用这种
    // std::unique_ptr<Entity> e0 = entity; // 错误
		entity->Print();
	}

	return 0;
}
class Entity
{
public:
	Entity()
	{
		std::cout << "Create Entity!" << std::endl;
	}
	~Entity()
	{
		std::cout << "Destroyed Entity!" << std::endl;
	}

	void Print() {};
};

离开作用域前,打印Create Entity!;离开作用域后,打印Destroyed Entity!

查看unique_ptr函数,会发现拷贝和构造函数都被删除,这是编译器防止程序员自掘坟墓,做出的提示!

在这里插入图片描述

3、shared_ptr

使用unique_ptr最大的缺点即是不能拷贝指针,所以,如果你喜欢分享,可以使用shared_ptr来弥补缺陷!

核心思想:

当复制或拷贝时,引用计数加1,当智能指针析构时,引用计数减1,如果计数为零,代表已经没有指针指向这块内存,那么我们就释放它!这就是 shared_ptr 采用的策略!

int main()
{
	// test1();
	
	{
		std::shared_ptr<Entity> sharedEntity = std::make_shared<Entity>();
		std::shared_ptr<Entity> e0 = sharedEntity; // 正确,增加引用计数
		entity->Print();
	}


	return 0;
}

4、weak_ptr

可以与shared一起使用,对于shared来说,它不会增加计数器,

int main()
{
	{
		std::shared_ptr<Entity> sharedEntity = std::make_shared<Entity>();
		std::weak_ptr<Entity> e0 = sharedEntity; // 不会增加计数器
		entity->Print();
	}


	return 0;
}

常见的智能指针即这几种,后面可能会手写智能指针,看后面更新吧!


参考
cpp_learners
努力学习的少年
哔哩哔哩

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python私教张大鹏 Vue3整合Vue Router之编程式导航

除了使用 <router-link> 创建 a 标签来定义导航链接&#xff0c;我们还可以借助 router 的实例方法&#xff0c;通过编写代码来实现。 导航到不同的位置 注意: 下面的示例中的 router 指代路由器实例。在组件内部&#xff0c;你可以使用 $router 属性访问路由&#xff…

spool 管道 小文件 mknod

Spool File In SQL*PLUS in Multiple Small Files ? (Doc ID 2152654.1)​编辑To Bottom In this Document Goal Solution APPLIES TO: Oracle Database - Enterprise Edition - Version 10.2.0.1 to 12.1.0.2 [Release 10.2 to 12.1] Oracle Database Cloud Schema Service…

城镇污水处理设施运维服务认证

初次申请认证时需提交的文件/资料 1、通用文件/资料(证明文件复印件需签字盖公章) ☐ 营业执照复印件、统一社会信用代码/组织机构代码证复印件 ☐ 增值税一般纳税人资格证复印件&#xff0c;或其他增值税一般纳税人资格认定文件复印件 ☐ 资质 或 许可证 复印件&#x…

DNS协议 | NAT技术 | 代理服务器

目录 一、DNS协议 1、DNS背景 2、DNS协议 域名 域名解析 二、NAT技术 1、NAT技术 2、NAPT技术 3、NAT技术的缺陷 三、代理服务器 1、正向代理服务器 2、反向代理服务器 一、DNS协议 域名系统&#xff08;Domain Name System&#xff0c;缩写&#xff1a;DNS&#…

Vue TypeScript 实战:掌握静态类型编程

title: Vue TypeScript 实战&#xff1a;掌握静态类型编程 date: 2024/6/10 updated: 2024/6/10 excerpt: 这篇文章介绍了如何在TypeScript环境下为Vue.js应用搭建项目结构&#xff0c;包括初始化配置、创建Vue组件、实现状态管理利用Vuex、配置路由以及性能优化的方法&#x…

vue2自定义指令

本节目标 快速入门v-loading 快速入门 指令对比 基本语法 使用: v-指令名"指令值"定义: 通过 directives 局部定义或者全局定义通过事件对象 el 可以拿到指令所在元素通过形参 binding 可以拿到指令的传值通过update钩子, 可以监听指令值的变化,进行更新操作 局部…

2024浙江省三支一扶报名流程!超详细图解!

2024浙江省三支一扶报名流程&#xff01;超详细图解&#xff01; 浙江省高校毕业生“三支一扶”报名即将开始&#xff0c;准备报考的同学们做好准备&#xff1a; &#x1f534;重点时间安排&#xff1a; 1、网络报名&#xff1a;6月11日9:00至6月18日17:00 2、资格审核&…

速卖通店铺防关联该怎么做?

大家都知道&#xff0c;想要进行多账号操作必须一再小心&#xff0c;否则会有很大的关联风险&#xff0c;而账号关联所带来的后果是卖家绝对不能轻视的&#xff0c;严重的话会导致封号&#xff0c;这样一来自己前期的辛苦运营就全都打水漂了&#xff0c;因此防关联很重要&#…

C++对象池设计与实现

目录 一、对象池简介 1.1 池化技术 1.2 什么是对象池 1.3 对象池分配策略 二、C new和delete运算符重载 三、实现一个对象池框架 3.1 策略接口 四、实现几种对象池的分配策略 4.1 数组策略 4.2 堆策略 ​编辑 4.3 栈策略 4.4 区块策略 一、对象池简介 1.1 池化技…

【C语言】插入排序(经典算法,建议收藏!!!)

目录 1、原理2、代码展示3、解析代码4、适用场景 1、原理 插入排序&#xff08;Insertion Sort&#xff09;是一种简单直观的排序算法&#xff0c;其原理可以简述如下&#xff1a; 1.分已排序区间和未排序区间: 将数组分为已排序区间和未排序区间。初始时&#xff0c;已排序区…

51单片机-独立按键控制灯灯灯

目录 简介: 一. 1个独立按钮控制一个灯例子 二. 在加一个独立按键,控制第二个灯 三. 第一个开关 开灯, 第二个开关关灯 四. 点一下开灯,在点一下关灯 五. 总结 简介: 51 单片机具有强大的控制能力&#xff0c;而独立按键则提供了一种简单的输入方式。 当把独立按键与 …

Vue 2看这篇就够了

Vue 2 技术文档 Vue.js 是一款用于构建用户界面的渐进式框架。与其他重量级框架不同的是&#xff0c;Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三方库或既有项目整合。而 Vue.js 2&#xff08;以下简称 Vue…

Leetcode 力扣113. 路径总和 II (抖音号:708231408)

给你二叉树的根节点 root 和一个整数目标和 targetSum &#xff0c;找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 叶子节点 是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum 22 输出&a…

【设计模式】结构型-桥接模式

当抽象与实现&#xff0c;各自独立&#xff0c; 桥接模式&#xff0c;如彩虹桥&#xff0c;连接两岸。 文章目录 一、类爆炸与代码重复二、桥接模式三、桥接模式的核心组成四、运用桥接模式五、桥接模式的应用场景六、小结推荐阅读 一、类爆炸与代码重复 场景假设&#xff1a…

标量、向量、矩阵、张量是什么?

参考视频&#xff1a;标量、向量、矩阵、张量-机器学习-李文哲AI人工智能培训_哔哩哔哩_bilibili 参考资料&#xff1a;深度学习基础&#xff1a;标量、向量、矩阵、张量_深度学习本质是矩阵-CSDN博客 标量是一个独立存在的数&#xff0c;比如线性代数中的一个实数5就可以被看…

每日一题——Python实现PAT乙级1019 数字黑洞(举一反三+思想解读+逐步优化)

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 点评代码的优缺点&#xff1a; 时间复杂度&#xff1a; 空间复杂度&#…

DAMA学习笔记(一)-数据管理

1.引言 数据管理(Data Management) 是为了 交付、 控制、 保护 并 提升 数据和信息资产的 价值 , 在其整个生命周期中制订 计划、 制度、 规程和实践 活动, 并 执行 和 监督 的过程。 数据管理专业人员(Data Management Professional) 是指 从事数据管理各方面的工作…

Cinema 4D 2024 软件安装教程、附安装包下载

Cinema 4D 2024 Cinema 4D&#xff08;C4D&#xff09;是一款由Maxon开发的三维建模、动画和渲染软件&#xff0c;广泛用于电影制作、广告、游戏开发、视觉效果等领域。Cinema 4D允许用户创建复杂的三维模型&#xff0c;包括角色、场景、物体等。它提供了多种建模工具&#x…

Flink 基于 TDMQ Apache Pulsar 的离线场景使用实践

背景 Apache Flink 是一个开源的流处理和批处理框架&#xff0c;具有高吞吐量、低延迟的流式引擎&#xff0c;支持事件时间处理和状态管理&#xff0c;以及确保在机器故障时的容错性和一次性语义。Flink 的核心是一个分布式流数据处理引擎&#xff0c;支持 Java、Scala、Pytho…

数据库期末设计——图书管理系统

目录 1.前置软件以及开发环境&#xff1a; 2.开发过程讲解 代码环节&#xff1a; 数据库代码 1.BookDao.java 2.BookTypeDao.java 3.UserDao.java 4.Book.java 5.BookType.java 6.User.java 7.DbUtil.java 8.Stringutil.java 9.BookAddInterFrm.java 10.BookMan…