[C++面试] 智能指针面试点(重点)续4
[C++面试] RAII资源获取即初始化(重点)-CSDN博客
[C++面试] 智能指针面试点(重点)-CSDN博客
[C++面试] 智能指针面试点(重点)续1-CSDN博客
[C++面试] 智能指针面试点(重点)续2-CSDN博客
[C++面试] 智能指针面试点(重点)续3-CSDN博客
一、入门
1、使用智能指针或者RAII技术过程中,如果出现了异常,会发生什么?
栈展开保证析构:C++的异常处理机制会确保所有已构造的局部对象析构函数被调用,无论是否发生异常
RAII
- RAII(资源获取即初始化)的核心是通过对象的构造函数获取资源,析构函数释放资源。
- 当异常发生时,C++会执行栈展开(Stack Unwinding),即销毁当前作用域及调用链中所有局部对象,触发析构函数。这一机制确保了即使抛出异常,资源仍会被自动释放
智能指针同理:栈展开(Stack Unwinding)
void processData() {auto ptr = std::make_unique<int>(42); // RAII对象构造时获取内存throw std::runtime_error("模拟异常"); // 抛出异常// 后续代码不会执行,但ptr的析构函数仍会被调用
} // 栈展开时,unique_ptr析构,自动释放内存
shared_ptr有什么不同的吗?
void sharedExample() {auto ptr1 = std::make_shared<int>(10);auto ptr2 = ptr1; // 引用计数+1throw std::logic_error("错误");
} // 栈展开时,引用计数减至0,释放内存
析构顺序:局部对象ptr2和ptr1会按照构造的逆序依次析构
ptr2析构:引用计数从2减少到1。ptr1析构:引用计数从1减少到0,此时对象的内存被释放,控制块(包含引用计数)也被销毁
多线程场景下呢?
shared_ptr的引用计数(_M_use_count)是原子变量(_Atomic_word),析构时的递减操作是线程安全的.
即使异常发生在多线程环境下,引用计数的修改也不会导致竞争条件
二、进阶
1、智能指针相互间赋值
1.1 unique_ptr 之间的赋值
左值不能直接赋值:unique_ptr 表示独占所有权,禁止普通左值之间的赋值,避免多个指针指向同一对象。
unique_ptr<int> a = make_unique<int>(5);
unique_ptr<int> b;
b = a; // 编译错误,a 是左值,直接赋值违反独占原则
右值可通过移动赋值:若为右值(如临时对象或通过 std::move 转换),则可移动赋值。此时原 unique_ptr 失去所有权(变为 nullptr)
unique_ptr<int> a = make_unique<int>(5);
unique_ptr<int> b = std::move(a); // 合法,a 变为 nullptr,b 接管对象
1.2 unique_ptr、shared_ptr 的赋值
unique_ptr 右值可赋值给 shared_ptr:shared_ptr 有显式构造函数,可接收 unique_ptr 右值(如临时对象或 std::move 转换后的对象)。此时 shared_ptr 接管对象所有权:
unique_ptr<int> uptr = make_unique<int>(10);
shared_ptr<int> sptr1 = std::move(uptr); // 合法,uptr 变为 nullptr shared_ptr<int> sptr2(make_unique<int>(20)); // 合法,临时 unique_ptr 作为右值
shared_ptr<int> sptr3 = make_unique<int>(42); // 隐式移动构造。在构造shared_ptr时传入unique_ptr的右值(如函数返回值),编译器会自动完成移动操作
unique_ptr 左值不可直接赋值给 shared_ptr:若直接用 unique_ptr 左值初始化 shared_ptr,会编译错误
unique_ptr<int> uptr = make_unique<int>(10);
shared_ptr<int> sptr3(uptr); // 编译错误,uptr 是左值
1.3 总结
- 允许转换的方向:
unique_ptr→shared_ptr(通过移动语义)。 - 禁止转换的方向:
shared_ptr→unique_ptr unique_ptr之间仅允许右值移动赋值;unique_ptr可通过右值(如std::move或临时对象)赋值给shared_ptr,但左值不行。
2、 shared_ptr<int*>有什么问题?
// 正确用法:shared_ptr<int> 管理 int 对象
shared_ptr<int> sp1 = make_shared<int>(10); // 直接管理 int 值 10 // 非常规用法:shared_ptr<int*> 管理 int* 指针
// 管理 int*,需确保 int* 指向的内存正确释放(此处虽合法但不推荐)
shared_ptr<int*> sp2 = make_shared<int*>(new int(20));
shared_ptr<int>:直接管理一个 int 类型的对象,智能指针内部存储的是 int 对象的指针(如 int*),并负责该 int 对象的内存释放。符合智能指针的设计初衷,直接管理对象内存。
shared_ptr<int*>:管理一个 int* 类型的指针(即指针本身成为智能指针管理的对象)。这种用法违背了智能指针简化对象管理的原则,因为 int* 指向的对象仍需确保其生命周期正确(虽然此处 int* 由 new int 分配,delete 合法,但代码逻辑易混淆)。
std::shared_ptr<int*> sptr(new int*(new int(42)), [](int** p) { delete *p; // 释放内层 int 对象delete p; // 释放外层 int* 指针}
);
需在自定义删除器中显式释放内层内存。
使用 shared_ptr<T[]>(C++17 及以上)
int main() {// 创建 shared_ptr 管理动态数组(C++17 起支持)std::shared_ptr<int[]> arr(new int[5]{1, 2, 3, 4, 5});// 直接通过 operator[] 访问元素for (int i = 0; i < 5; ++i) {arr[i] = i * 10; // 修改元素std::cout << arr[i] << " "; // 输出:0 10 20 30 40}// 无需手动释放,shared_ptr 自动调用 delete[]return 0;
}
自定义删除器(兼容 C++11/14)
int main() {// 定义删除器(Lambda 表达式)auto array_deleter = [](int* ptr) {delete[] ptr; // 必须显式调用 delete[]std::cout << "动态数组内存已释放\n";};// 创建 shared_ptr 并传入删除器std::shared_ptr<int> arr(new int[5]{1, 2, 3, 4, 5}, array_deleter);// 通过 get() 获取原始指针访问元素int* raw_ptr = arr.get();for (int i = 0; i < 5; ++i) {raw_ptr[i] = i * 10; // 修改元素std::cout << raw_ptr[i] << " "; // 输出:0 10 20 30 40}// 析构时自动调用 array_deleterreturn 0;
}
三、其他
警告:
永远不要将资源分配结果赋值给原始指针。无论使用哪种资源分配方法,都应当立即将资源指针存储在智能指针 unique_ptr 或 shared_ptr 中,或使用其他 RAII 类。RAII 代表 Resource Acquisition Is Initialization (资源获取即初始化)。RAII 类获取某个资源的所有权,并在适当的时候进行释放。—— 《C++20高级编程(上册)》
相关文章:
[C++面试] 智能指针面试点(重点)续4
[C面试] RAII资源获取即初始化(重点)-CSDN博客 [C面试] 智能指针面试点(重点)-CSDN博客 [C面试] 智能指针面试点(重点)续1-CSDN博客 [C面试] 智能指针面试点(重点)续2-CSDN博客 …...
java项目分享-分布式电商项目附软件链接
今天来分享一下github上最热门的开源电商项目安装部署,star 12.2k,自行安装部署历时两天,看了这篇文章快的话半天搞定!该踩的坑都踩完了,软件也打包好了就差喂嘴里。 项目简介 mall-swarm是一套微服务商城系统…...
16变量命名风格
给变量/函数/文件/类 起名字, 非常有讲究的~~ 1.起的名字要有描述性.不要使用 abc,xyz 这种比较无规律的名字来描述 2.如果名字比较长,由多个单词构成的,就需要使用适当的方式来进行区分不同单词 C中,偏好使用_来进行单词的分割. 形如: student_count(变量) unordered_map(stl容…...
【LVS】负载均衡群集部署(DR模式)
部署前IP分配 DR服务器:192.168.166.101 vip:192.168.166.100 Web服务器1:192.168.166.104 vip:192.168.166.100 Web服务器2:192.168.166.107 vip:192.168.166.100 NFS服务器:192.168.166.108 …...
链表的操作-反转链表
链表 160相交链表 代码 class Solution { public:ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {ListNode* h1headA;ListNode* h2headB;while(h1&&h2){if(h1!h2){h1h1->next;h2h2->next;}else{return h1;}}if(h1nullptr){h1headB;}else{h…...
Linux安装Cmake (Centos 7.9)
cmake安装 这个虽然已经更新到了4.0.0版本了,但是我们要用3.5版本的,因为这个比较稳定 官方地址:https://github.com/Kitware/CMake/releases/tag/v3.5.0,选择那个cmake-3.5.0-Linux-x86_64.tar.gz下载, 首先解压文…...
Node.js v22.14.0 多平台安装指南:Windows、Linux 和 macOS 详细教程
Node.js作为现代Web开发的基石,持续为开发者带来性能提升和新特性支持。本文将详细介绍在Windows、macOS和Linux系统上安装最新Node.js的多种方法,助您快速搭建高效的JavaScript开发环境。 📦 当前最新版本 截至2025年4月,Node.…...
Netty源码—10.Netty工具之时间轮一
大纲 1.什么是时间轮 2.HashedWheelTimer是什么 3.HashedWheelTimer的使用 4.HashedWheelTimer的运行流程 5.HashedWheelTimer的核心字段 6.HashedWheelTimer的构造方法 7.HashedWheelTimer添加任务和执行任务 8.HashedWheelTimer的完整源码 9.HashedWheelTimer的总结…...
C++虚函数与抽象类
一、虚函数  **;类中定义不同类中的同名函数的多态的行为**,主要是通过虚函数来实现。 在类的成员函数前加virtual关键字。虚函数是实现包含多态的基础。这里需要说明的是当基类里有虚函数且派生类中重新声明了和基类虚函数相同的函数,那…...
鸿蒙项目笔记(1)
一、核心内容-商城 1、装饰器的拓展使用,基础组件的熟悉。 2、引入基础动画实战,页面属性动画、页面跳转动画、自定义页面翻页等。 3、一次开发,多端部署。 4、本地数据库实战,涉及多种本地数据存储方式。 5、路由导航&#…...
*快排延伸-自省排序
此节是学有余力的人去看,如果没时间,不看也没关系,只要知道代码就可以了! 自省排序的思路是自我侦测和反省,快速排序如果递归深度太深,其算法的效率可能被大幅度削弱,这就需要借助其他的算法进…...
三.微服务架构中的精妙设计:服务注册/服务发现-Eureka
一.使用注册中心背景 1.1服务远程调用问题 服务之间远程调⽤时, 我们的URL是写死的 String url "http://127.0.0.1:9090/product/" orderInfo.getProductId(); 缺点: 当更换机器, 或者新增机器时, 这个URL就需要跟着变更, 就需要去通知所有的相关服…...
python-leetcode 63.搜索二维矩阵
题目: 给一个满足两条属性的m*n的整数矩阵: 每行中的整数从左到右按非严格递增顺序排列 每行的第一个整数大于前一行的最后一个整数 给一个整数target,如果target在矩阵中,返回true,否则返回false 方法一:两次二分查找 由于每…...
后端框架入门:Django
Django 基础:模型、视图、模板Django REST Framework 的使用一、Django 概述 Django 是一个 高效、灵活、可扩展 的 Python Web 框架,主要用于快速开发 Web 应用 和 REST API。 📌 Django 的优势: ✅ MTV 架构:模型(Model)、视图(View)、模板(Template)分离,便于…...
从零构建大语言模型全栈开发指南:第四部分:工程实践与部署-4.3.2知识库增强与外部API集成(代码示例:HTTP节点与检索增强生成)
👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 知识库增强与外部API集成:HTTP节点与检索增强生成实战4.3.2 知识库增强与外部API集成(代码示例:HTTP节点与检索增强生成)1. 核心挑战与优化目标1.1 技术瓶颈分析1.2 设计目标2. 关键技术方案2.1 知识…...
音视频入门基础:MPEG2-TS专题(26)——通过FFmpeg命令使用RTP发送TS流
音视频入门基础:MPEG2-TS专题系列文章: 音视频入门基础:MPEG2-TS专题(1)——MPEG2-TS官方文档下载 音视频入门基础:MPEG2-TS专题(2)——使用FFmpeg命令生成ts文件 音视频入门基础…...
blender二次元上色
前: 后:(脸自己会发光) 参考:05-模型导入与材质整理_哔哩哔哩_bilibili...
2025年2月一区SCI-壮丽细尾鹩莺算法Superb Fairy-wren Optimization-附Matlab免费代码
引言 本期介绍一种新的元启发式算法——壮丽细尾鹩莺优化算法Superb Fairy-wren Optimization algorithm,SFOA。该算法结合了壮丽细尾鹩莺群体中幼鸟的发育,繁殖后喂养幼鸟的行为,以及它们躲避捕食者的策略,于2025年2月最新发表在…...
Linux系统禁用swap
Linux系统禁用swap sed -ri s/.*swap.*/#&/ /etc/fstab大家之前禁用swap用上面的命令,也就是把"/etc/fstab"文件里包含swap的那行注释了,然后重启系统swap就被禁用了。 可是到了Ubuntu 20.04之后、CentOS Stream 10、openEuler 24.04、O…...
Hadoop•踩过的SHIT
听说这里是目录哦 ssh登录Permission denied, please try again💩要发癫🥲 centos7 yum报错:cannot find a valid baseurl for repo:base/7/x86_64💩FinalShell重连失效💩ssh免密登录显示 No route to hostὊ…...
闭环SOTA!北航DiffAD:基于扩散模型实现端到端自动驾驶「多任务闭环统一」
端到端自动驾驶目前是有望实现完全自动驾驶的一条有前景的途径。然而,现有的端到端自动驾驶系统通常采用主干网络与多任务头结合的方式,但是它们存在任务协调和系统复杂度高的问题。为此,本文提出了DiffAD,它统一了各种驾驶目标并…...
Docker Registry 清理镜像最佳实践
文章目录 registry-clean1. 简介2. 功能3. 安装 docker4. 配置 docker5. 配置域名解析6. 部署 registry7. Registry API 管理8. 批量清理镜像9. 其他10. 参考registry-clean 1. 简介 registry-clean 是一个强大而高效的解决方案,旨在简化您的 Docker 镜像仓库管理。通过 reg…...
JavaScript重难点突破:期约与异步函数
同步和异步 同步(Synchronous) 定义:任务按顺序依次执行,前一个任务完成前,后续任务必须等待。 特点:阻塞性执行,程序逻辑直观,但效率较低 异步(Asynchron…...
蓝桥杯高频考点——高精度(含C++源码)
高精度 前言高精度加法例题思路及代码solution 1(初阶版 40分)solution 2(完全体 AC) 高精度乘法例题思路及代码solution 1(TLE 但是代码很清晰)solution 1的问题solution 2(优化 AC)…...
(Kotlin) Android使用DialogX实现iOS风格底部弹窗(带Toggle开关)
本文将详细介绍如何使用DialogX库实现一个iOS风格的底部弹窗,包含图标、文本和Toggle开关的列表项。 实现步骤 1. 添加依赖 在build.gradle文件中添加: implementation com.github.kongzue.DialogX:DialogX:0.0.49.beta14 implementation com.github.ko…...
【机器人】复现 GraspNet 端到端抓取点估计 | PyTorch2.3 | CUDA12.1
GraspNet是通用物体抓取的大规模基准的基线模型,值得学习和复现。 本文分享使用较新版本的PyTorch和CUDA,来搭建开发环境。 论文地址:GraspNet-1Billion: A Large-Scale Benchmark for General Object Grasping 开源地址:https:…...
视频联网平台智慧运维系统:智能时代的城市视觉中枢
引言:破解视频运维的"帕累托困境" 在智慧城市与数字化转型浪潮中,全球视频监控设备保有量已突破10亿台,日均产生的视频数据量超过10万PB。然而,传统运维模式正面临三重困境: 海量设备管理失序:…...
《网络管理》实践环节03:snmp服务器上对网络设备和服务器进行初步监控
兰生幽谷,不为莫服而不芳; 君子行义,不为莫知而止休。 应用拓扑图 3.0准备工作 所有Linux服务器上(服务器和Agent端)安装下列工具 yum -y install net-snmp net-snmp-utils 保证所有的HCL网络设备和服务器相互间能…...
ubuntu中使用安卓模拟器
本文这里介绍 使用 android studio Emulator , 当然也有 Anbox (Lightweight), Waydroid (Best for Full Android Experience), 首先确保自己安装了 android studio ; sudo apt update sudo apt install openjdk-11-jdk sudo snap install…...
【Qt】QList<T> list(n)构造函数创建列表时元素 T的默认值
Qt 6支持。 在 Qt 中,当使用 QList<T> list(n); 构造函数创建列表时,元素 T 的默认值取决于其类型的默认构造函数或值初始化规则。以下是常见数据类型的默认值分析: 1. 基本数据类型(POD 类型,Plain Old Data&a…...
