当前位置: 首页 > news >正文

C++智能指针shared_ptr详解

智能指针shared_ptr详解

  • 一、简介
  • 二、底层原理
    • 2.1、引用计数
    • 2.2、shared_ptr的构造和析构
    • 2.3、shared_ptr的共享和拷贝
    • 2.4、循环引用问题
  • 三、shared_ptr的使用
    • 3.1、创建一个shared_ptr
    • 3.2、共享一个shared_ptr
    • 3.3、使用删除器
    • 3.4、解除关联
  • 四、使用示例
  • 总结

一、简介

C++智能指针shared_ptr是一种可以自动管理内存的智能指针,它是C++11新增的特性之一。与传统指针不同,shared_ptr可以自动释放所管理的动态分配对象的内存,并避免了手动释放内存的繁琐操作,从而减少了内存泄漏和野指针的出现。

shared_ptr是一个模板类,通过引用计数器实现多个智能指针共享对一个对象的所有权。每次复制一个shared_ptr对象时,该对象的引用计数器会增加1,当最后一个shared_ptr对象被销毁时,引用计数器减1,如果引用计数器变为0,则释放所管理的对象的内存。

使用shared_ptr需要包含头文件,并且可以通过以下方式创建:

std::shared_ptr<int> p(new int(10));

上面的代码创建了一个shared_ptr对象p,它指向一个动态分配的int类型对象,初始值为10。

在使用shared_ptr时,需要注意以下几点:

  1. 不要使用裸指针来初始化shared_ptr,否则可能导致多次删除同一个对象的情况。

  2. 避免在shared_ptr中存储数组,因为shared_ptr只能处理单个对象的释放,而不能正确地处理数组的销毁。

  3. 可以通过自定义删除器(deleter)来实现对对象的特定方式的释放。

  4. shared_ptr可以作为函数参数传递,但要注意避免循环引用的问题,否则会导致内存泄漏。

shared_ptr是一种方便且安全的内存管理工具,能够有效地避免内存泄漏和野指针的出现。

二、底层原理

在这里插入图片描述

2.1、引用计数

shared_ptr的核心是引用计数技术。在每个shared_ptr对象中,都有一个指向所管理对象的指针和一个整型计数器。这个计数器统计有多少个shared_ptr对象指向该所管理对象。当一个新的shared_ptr对象指向同一块内存时,该内存的引用计数就会增加1。当一个shared_ptr对象不再指向该内存时,该内存的引用计数就会减少1。当引用计数为0时,说明没有任何shared_ptr对象指向该内存,此时该内存将会被自动释放。

2.2、shared_ptr的构造和析构

  1. shared_ptr的构造函数需要一个指针作为参数,该指针指向要被管理的对象。当一个新的shared_ptr对象被创建时,它会尝试增加所管理对象的引用计数。如果该对象还未被其他shared_ptr对象管理,则会创建一个新的引用计数,并将其设置为1。否则,它会与已经存在的shared_ptr对象共享同一个引用计数。

  2. shared_ptr的析构函数会尝试减少所管理对象的引用计数。如果引用计数变成0,则会自动释放所管理对象的内存。

  3. shared_ptr的控制块(包含引用计数和删除器等信息)会在最后一个指向所管理对象的shared_ptr析构时被释放。当引用计数减为0时,就说明没有任何shared_ptr对象指向该所管理对象了,此时shared_ptr会自动调用删除器,并释放掉控制块。由于shared_ptr可以共享同一个控制块,因此只有所有shared_ptr对象都析构后,控制块才能被释放。如果一个shared_ptr对象使用reset()方法手动解除与所管理对象的关联,也会相应地减少引用计数,当引用计数变成0时,控制块也会被释放。

2.3、shared_ptr的共享和拷贝

shared_ptr可以与其他shared_ptr对象共享同一个指向对象的指针。当一个shared_ptr对象被复制时,它所管理的对象的引用计数也会增加1。因此,任何一个持有相同指针的shared_ptr对象都可以通过更改其所管理对象的状态来影响所有其他shared_ptr对象。

2.4、循环引用问题

shared_ptr在处理循环引用问题时非常有效。例如,如果一个对象A包含指向另一个对象B的shared_ptr,而对象B也包含指向对象A的shared_ptr,则这两个对象将形成循环引用。在这种情况下,如果使用普通指针,可能会出现内存泄漏。但是,由于shared_ptr使用引用计数技术,当没有任何其他shared_ptr对象引用这两个对象时,它们将被正确地释放。

三、shared_ptr的使用

创建shared_ptr对象的语法有以下几种方式:

  1. 通过new关键字创建
std::shared_ptr<int> p(new int);
  1. 通过make_shared函数创建,该函数可以避免使用new关键字
std::shared_ptr<int> p = std::make_shared<int>();
  1. 传递指针和删除器作为参数创建
void my_deleter(int* p) {delete p;
}std::shared_ptr<int> p(new int, my_deleter);
  1. 传递指针、删除器和分配器作为参数创建
void my_deleter(int* p) {delete p;
}struct MyAllocator {void* allocate(size_t size);void deallocate(void* ptr, size_t size);
};MyAllocator my_allocator;std::shared_ptr<int> p(new int, my_deleter, my_allocator);
  1. 从另一个shared_ptr对象创建
std::shared_ptr<int> p1(new int);
std::shared_ptr<int> p2(p1);
  1. 使用移动语义从另一个shared_ptr对象创建
std::shared_ptr<int> p1(new int);
std::shared_ptr<int> p2(std::move(p1));

3.1、创建一个shared_ptr

使用shared_ptr创建一个智能指针非常简单,只需要将一个指向动态分配内存的裸指针作为参数传递给shared_ptr的构造函数即可:

// 创建一个int类型的智能指针
std::shared_ptr<int> p(new int(10));

3.2、共享一个shared_ptr

shared_ptr可以与其他shared_ptr对象共享同一个指向对象的指针,这样就可以避免多次动态分配内存和释放内存的问题。共享一个shared_ptr可以通过复制构造函数和赋值运算符实现:

// 复制构造函数
std::shared_ptr<int> p1(new int(10));
std::shared_ptr<int> p2(p1);// 赋值运算符
std::shared_ptr<int> p3(new int(10));
std::shared_ptr<int> p4;
p4 = p3;

注意:共享一个shared_ptr会增加所管理对象的引用计数。因此,任何一个持有相同指针的shared_ptr对象都可以通过更改其所管理对象的状态来影响所有其他shared_ptr对象。

3.3、使用删除器

除了管理所分配的内存外,shared_ptr还可以使用删除器(deleter)来管理对象。删除器是一个函数或者函数对象,用于在shared_ptr释放所管理对象时执行特定的操作。删除器可以通过shared_ptr的模板参数指定:

// 使用Lambda表达式作为删除器
std::shared_ptr<int> p(new int(10), [](int* p){ delete[] p; });

3.4、解除关联

如果需要解除shared_ptr与所管理对象的关联,可以使用reset()方法:

std::shared_ptr<int> p(new int(10));
p.reset();

注意:当调用reset()方法后,所管理对象的引用计数会减少1。如果引用计数变成0,则会自动释放所管理对象的内存。

四、使用示例

#include <memory>
#include <iostream>using namespace std;class MyClass {
public:MyClass() { cout << "MyClass constructor" << endl; }~MyClass() { cout << "MyClass destructor" << endl; }void printInfo() { cout << "This is MyClass" << endl; }
};int main() {shared_ptr<MyClass> p1(new MyClass()); // 创建一个shared_ptr指向MyClass对象shared_ptr<MyClass> p2 = p1; // p1和p2都指向同一个MyClass对象p1->printInfo(); // 访问MyClass对象的成员函数p2.reset(); // 释放p2所指向的MyClass对象p1->printInfo(); // 由于p1仍然指向MyClass对象,所以此处输出"This is MyClass"return 0;
}

上述代码中,通过调用shared_ptr<MyClass>构造函数创建了两个指针p1和p2,并且它们都指向一个MyClass对象。我们调用reset()函数来释放p2所指向的MyClass对象,但是由于p1仍然指向该对象,所以在调用p1->printInfo()时仍然输出"This is MyClass"。当程序结束时,p1所指向的MyClass对象会被自动释放。

可以看到,使用shared_ptr可以很方便地避免内存泄漏和悬空指针等问题。另外,需要注意的是,shared_ptr指针之间的赋值和拷贝操作都会增加指向对象的引用计数,即使一个指针已经释放了它所指向的对象,只要其他指针还在使用该对象,该对象就不会被自动删除。因此,在使用shared_ptr时需要注意对象的生命周期,避免产生意外的副作用。

总结

智能指针是C++中一种重要的语言机制,其中shared_ptr是最常用和最经典的智能指针之一。

  1. shared_ptr是一种引用计数的智能指针,可以共享同一个对象。

  2. 使用shared_ptr时,需要包含头文件< memory >。

  3. 创建shared_ptr对象时,可以直接将原始指针作为参数传递给构造函数,也可以使用make_shared函数进行创建。

  4. 对象的引用计数会在shared_ptr对象初始化、复制、释放时自动更新。

  5. 当某个shared_ptr对象被销毁时,它所指向的对象的引用计数会减少,如果引用计数为0,则该对象会被自动删除。

  6. 通过get函数可以获取shared_ptr对象所管理的原始指针。

  7. 通过reset函数可以重新绑定shared_ptr对象所管理的原始指针。

  8. 可以使用unique函数判断shared_ptr对象是否唯一拥有原始指针。

  9. 通常情况下,shared_ptr对象应该在栈上创建,而不是使用new运算符在堆上创建。

  10. 在多线程环境下使用shared_ptr时需要注意,需要采取线程安全措施,比如使用锁来保证引用计数的正确性。

  11. shared_ptr是C++11中STL的一部分,它是一个模板类,用于管理动态地分配对象的内存。shared_ptr可以自动完成内存管理,确保内存被正确释放,并且非常易于使用。

  12. shared_ptr是一个强大的智能指针类,它利用引用计数技术来管理动态分配的对象的内存。shared_ptr可以避免循环引用和内存泄漏等问题,并且易于使用,是C++程序员必不可少的工具之一。

在这里插入图片描述

相关文章:

C++智能指针shared_ptr详解

智能指针shared_ptr详解 一、简介二、底层原理2.1、引用计数2.2、shared_ptr的构造和析构2.3、shared_ptr的共享和拷贝2.4、循环引用问题 三、shared_ptr的使用3.1、创建一个shared_ptr3.2、共享一个shared_ptr3.3、使用删除器3.4、解除关联 四、使用示例总结 一、简介 C智能指…...

家政服务APP小程序开发功能详解

随着人们生活水平的提高&#xff0c;对家政服务的要求也越来越高。而传统的到家政公司寻找服务人员的方法显然已经无法满足人们需求&#xff0c;取而代之的是线上预约家政服务。家政服务App小程序软件可以满足用户在线预约&#xff0c;还可以根据自己的需求定制家政服务、选择家…...

【C++】deque的实现原理简单介绍

前言 deque被称为双端队列&#xff0c;它的出现主要是为了结合vector和list的优点并减小它们的缺点&#xff0c;实际上deque确实结合了vector和list的优点减小了它们的缺点&#xff0c;但是它的结合也让它自己的优点没有原始的vector和list那么极致&#xff0c;导致deque变得很…...

UWB隧道人员定位技术应用,施工作业安全精准保障

隧道施工的安全不仅关系到工程项目的质量和施工效率&#xff0c;也关系到我国的资金安全、施工人员和人民的生命财产安全。如何有效加强隧道施工的安全管理能力&#xff0c;成为隧道施工企业管理者最关心的问题。国家铁道局在《关于加强铁路隧道工程安全工作的若干意见》中指出…...

15.2 矩阵链乘法

1.代码 public class MatrixChainMultiplication {public static void main(String[] args) { // 在该代码中&#xff0c;我们首先创建了两个n * n的矩阵m和s&#xff0c;分别用于记录最优值和分割点。 其中m 矩阵 通过i j 来显示在i到j的矩阵链中最优解 // // …...

向隐形冠军学习:聚焦人效,用时间管理提效益

注&#xff1a; 本文来源于盖雅工场联合创始人兼CEO 章新波 在2023狮山论坛“ 向隐形冠军学习&#xff1a; 聚焦人效&#xff0c;用时间管理提效益 ”的主题分享。 文&#xff5c;章新波 整理 &#xff5c;盖雅学苑 在人力资源行业以及各大企业&#xff0c;「人效」这个词…...

Protocol Buffers Go Generated Code Guide

Protocol Buffers Go 代码生成指南 本主题准确描述了协议缓冲区编译器为任何给定的协议定义生成的Go代码。 编译器调用 协议缓冲区编译器需要一个插件来生成Go 代码。使用Go 1.16或更高版本安装&#xff0c;方法是运行&#xff1a; go install google.golang.org/protobuf/…...

Python VTK STL 映射三维模型表面距离

目录 前言&#xff1a; 效果&#xff1a; 实现步骤&#xff1a; Code: 前言&#xff1a; 本文介绍了Python VTK映射三维模型表面距离&#xff0c;通过如何使用VTK计算两个三维模型(stl)的表面距离&#xff0c;并将其距离值以颜色映射到模型&#xff0c;可用于对比 两相模型…...

C# 异常处理机制和常见的异常类型

在 C# 中&#xff0c;异常处理是一个非常重要的概念&#xff0c;它可以让我们在程序发生错误时进行有效的处理&#xff0c;使程序具备更好的鲁棒性。C# 异常处理机制基于 try-catch-finally 语句块&#xff0c;其基本用法如下&#xff1a; try {// 可能会抛出异常的代码 } cat…...

【0187】客户端身份验证配置文件视图之pg_hba_file_rules

文章目录 1. 客户端身份验证配置文件视图2. 视图效果相关阅读: 【0179】配置PostgreSQL以允许远程连接 【0180】PG内核通过pg_hba.conf完成客户端认证(1) 【0181】PG内核通过pg_hba.conf完成客户端认证(2)...

模糊层次分析法(FAHP)Python实现

文章目录 理论基础三角模糊数概念参考 Python源码测试 理论基础 \quad 模糊层次分析法&#xff08; F A H P FAHP FAHP&#xff09;将模糊理论&#xff08; F u z z y S e t Fuzzy Set FuzzySet&#xff09;嵌入到基本层次分析法&#xff08; A H P AHP AHP&#xff09;中。 A …...

gdb切换窗口焦点

为了辅助调试&#xff0c;一般会使用layout src&#xff0c;调起TUI显示代码&#xff1a; 然而这种情况下我们写命令很不方便&#xff0c;无法方便地使用上一条命令、退格等。 按动上下左右方向键盘只会移动代码框&#xff0c;然而在伪终端下&#xff0c;可以用鼠标滚轮来上下…...

【Spring Security】 入门实战

文章目录 一、基本概念二、Spring Security第一个程序三、Spring Security没有生效四、修改默认账号密码&#xff08;appliction.yml&#xff09;五、修改默认账号密码&#xff08;配置类&#xff09;六、Spring Security的三个configure方法七、Spring Security的三种身份的验…...

SpringBoot的Interceptor拦截器的简介和实际使用

拦截器&#xff08;Interceptor&#xff09; 概念&#xff1a;是一种动态拦截方法调用的机制&#xff0c;类似于过滤器。Spring框架中提供的&#xff0c;用来动态拦截控制器方法的执行。 作用&#xff1a;拦截请求&#xff0c;在指定的方法调用前后&#xff0c;根据业务需要执行…...

5个面向Python高级开发者的技巧

使用这些用于自定义类行为、编写并发代码、管理资源、存储和操作数据以及优化代码性能的高级技术来探索 Python 的深度。 本文探讨了 Python 中的五个高级主题&#xff0c;它们可以为解决问题和提高代码的可靠性和性能提供有价值的见解和技术。从允许您在定义类时自定义类行为的…...

Nginx简介

Nginx是什么&#xff1f;可以做什么事情&#xff1f; Nginx是高性能的HTTP和反向代理的web服务器&#xff0c;处理高并发的能力十分强大&#xff0c;能经受高负载的考研&#xff0c;有报告表明能能支持高达50000个并发连接数。 特点 占有内存少&#xff1a;一万个长连接&…...

十五分钟带你学会 Electron

文章目录 什么是 Electron为什么要选择 Electron安装 Electron桌面CSDN实战Electron 基础配置Electron 进程主进程渲染进程主进程与渲染进程的区别主进程与渲染进程的通信 Electron 跨平台问题Electron 部署打包应用程序发布应用程序 Electron 跨端原理总结 什么是 Electron E…...

设计模式-结构型模式之桥接模式

2. 桥接模式 2.1. 模式动机 设想如果要绘制矩形、圆形、椭圆、正方形&#xff0c;我们至少需要4个形状类&#xff0c;但是如果绘制的图形需要具有不同的颜色&#xff0c;如红色、绿色、蓝色等&#xff0c;此时至少有如下两种设计方案&#xff1a; 第一种设计方案是为每一种形状…...

软件测试工程师为什么要写测试用例?

软件测试工程师为什么要写测试用例&#xff1f;相信从事软件测试行业的从业者来讲&#xff0c;测试用例并不陌生。因为测试用例不仅仅是一组简单的文档&#xff0c;它包含前提条件、输入、执行条件和预期结果等等重要内容&#xff0c;并且能够完成一定的测试目的和需求。下面本…...

【DAY40】VUE练习

DOS命令&#xff1a; DOS&#xff08;Disk Operating System&#xff09;是一种操作系统&#xff0c;它使用命令行界面&#xff08;Command Prompt&#xff09;进行交互。在 DOS 中&#xff0c;有一些常用的命令&#xff0c;可以用来定位目录、创建、删除、拷贝文件和目录&…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...