C++11QT复习 (七)
智能指针雏形
- **Day7-1 智能指针雏形:独占语义与共享语义**
- **1. 独占语义与共享语义**
- **1.1 Circle 类:示例类**
- **2. 拷贝构造:独占语义(Unique Ownership)**
- **2.1 代码解析**
- **3. 拷贝构造:共享语义(Shared Ownership)**
- **3.1 代码解析**
- **4. 智能指针 std::unique_ptr 和 std::shared_ptr**
- **4.1 代码解析**
- **5. 移动语义(Move Semantics)**
- **5.1 代码解析**
- **总结**
Day7-1 智能指针雏形:独占语义与共享语义
1. 独占语义与共享语义
在 C++ 中,拷贝构造的语义可以分为独占语义和共享语义。
- 独占语义(Unique Ownership):每个对象拥有一块独立的内存,拷贝时进行深拷贝。
- 共享语义(Shared Ownership):多个对象共享同一块内存,拷贝时进行浅拷贝,通常需要引用计数来管理资源。
C++ 标准库提供了 std::unique_ptr 和 std::shared_ptr 来实现这两种语义。
1.1 Circle 类:示例类
Circle 类是一个普通的对象类,包含构造函数、析构函数、成员变量和方法。
// Circle.h
#pragma once
#include <iostream>
#include <cmath>
using namespace std;//关键字
//const
const int global_a = 10;
//static
static int s_b = 10;
//extern
extern int SIZE = 10;
//三者的用途:const 修饰常量,static 修饰全局变量,extern 修饰外部变量class Circle
{
public:Circle(double r = 0): _r(r){cout << "Circle(double r = 0)" << endl;}Circle(double r, char* name): _r(0), _name(new char[strlen(name) + 1]){strcpy_s(_name, strlen(name) + 1, name);cout << "Circle(double r, char* name)" << endl;}~Circle(){cout << "~Circle()" << endl;delete[] _name;}double getRadius() const { return _r; }void setRadius(double r) { _r = r; }double getArea() const { return M_PI * _r * _r; }private:double _r;char* _name;
};
2. 拷贝构造:独占语义(Unique Ownership)
UniqueClass 实现了独占语义,即对象的拷贝会创建新的独立对象,保证每个对象都拥有独立的内存。
// ShareClass.h
class UniqueClass
{int times = 0;
public:UniqueClass(int a): _data(new int(a)){}~UniqueClass(){delete _data;_data = nullptr;}// 深拷贝构造函数//UniqueClass(const UniqueClass& rhs)// :_data(new int(*rhs.data))//{// cout << "Call desctructor";// times++;// cout << times << endl;//}//在这段代码中,rhs 不是指针,而是一个 UniqueClass 类型的引用。// *rhs._data 是对 rhs 对象的 _data 成员指针进行解引用。UniqueClass(const UniqueClass& rhs): _data(new int(*rhs._data)) // 修复了错误的冒号和成员变量名称{cout << "Call constructor";times++;cout << times << endl;}/*1. UniqueClass(const UniqueClass & rhs) 是 UniqueClass 的拷贝构造函数。它接受一个 UniqueClass 类型的常量引用 rhs 作为参数。2. : _data(new int(*rhs._data)) 是成员初始化列表的一部分。它的作用是初始化 _data 成员变量。3. rhs._data 是对 rhs 对象的 _data 成员指针的访问。4. * rhs._data 是对 rhs._data 指针的解引用,获取指针指向的整数值。5. new int(*rhs._data) 创建了一个新的 int 对象,并将 * rhs._data 的值复制到这个新的 int 对象中。然后将新创建的 int 对象的指针赋值给 _data 成员变量。这样做的目的是在拷贝构造函数中为新对象分配一个新的内存空间,并将原对象的 _data 成员指针指向的值复制到新对象的 _data 成员指针指向的内存中。这确保了每个 UniqueClass 对象都有自己独立的 _data 内存空间,避免了多个对象共享同一块内存,从而防止潜在的内存管理问题。*//*传入的参数可以修改,修改后不可以再使用,最好当成右值使用*///移动构造函数的写法(C++11 移动构造函数,接受右值)// 拷贝指针,并断掉源对象对内存的引用(置空)// 如果传入参数本身是右值,没有任何副作用,因为调用结束,它就不在了// 但传入的如果是个左值转换来的右值,那要注意,充当了右值,右值的语义就是临时的,// 转瞬即时的,所以这个左值也应看成已逝的事物,不可以再使用UniqueClass(UniqueClass&& rhs):_data(rhs._data){rhs._data = nullptr;}// C++11 移动赋值运算符,接受右值,和移动构造同理UniqueClass& operator=(UniqueClass&& rhs){_data = rhs._data;rhs._data = nullptr;}private:int* _data;
};
2.1 代码解析
- 拷贝构造函数:创建新对象时,为
_data申请新的内存,保证对象的独占性。 - 移动构造函数:从右值拷贝指针,并将原对象的指针置空,避免重复释放内存。
- 移动赋值运算符:清理当前对象的内存,然后从右值拷贝指针,并清空右值的指针。
3. 拷贝构造:共享语义(Shared Ownership)
SharedClass 采用引用计数管理共享的内存。
class SharedClass
{
public:static int count; // 静态引用计数int* _data;SharedClass(int a) : _data(new int(a)) {}// 拷贝构造,拷贝指针,增加引用计数SharedClass(const SharedClass& r): _data(r._data){count++;}// 拷贝赋值,拷贝指针,增加引用计数SharedClass& operator=(const SharedClass& r){if (this != &r){_data = r._data;count++;}return *this;}// 析构时注意减少引用计数,归0时释放堆内存~SharedClass(){--count;if (count == 0){delete _data;}}
};int SharedClass::count = 1;
3.1 代码解析
- 引用计数
count:确保多个对象共享同一块内存。 - 拷贝构造函数:增加引用计数。
- 析构函数:当
count == 0时,释放_data。
4. 智能指针 std::unique_ptr 和 std::shared_ptr
C++ 提供 std::unique_ptr 和 std::shared_ptr,分别对应独占语义和共享语义。
void testSmartPointer()
{std::unique_ptr<int> unique1 = std::make_unique<int>(10);// std::unique_ptr<int> unique2 = unique1; // 错误:无法复制 unique_ptrstd::shared_ptr<int> share1 = std::make_shared<int>(10);std::shared_ptr<int> share2 = share1;cout << "share2 use_count() = " << share2.use_count() << endl;
}
4.1 代码解析
std::unique_ptr禁止拷贝,确保对象独占内存。std::shared_ptr可以拷贝,使用引用计数管理内存。
5. 移动语义(Move Semantics)
void testMoveSemantic()
{UniqueClass u1(10);cout << "u1.data = " << u1._data << endl; cout << "*(u1)._data = " << * (u1)._data << endl; //UniqueClass u2 = (UniqueClass&&)u1;//等价于UniqueClass u2 = std::move(u1);// move将uc1这个左值转为右值,即(UniqueClass&&)uc1;cout << "u2.data = " << u2._data << endl;cout << "*(u2)._data = " << *(u2)._data << endl;if (u1._data = nullptr){cout << "u1 is gone " << endl;}
}
5.1 代码解析
std::move(u1)将u1变为右值,调用移动构造函数。u1._data = nullptr,原对象u1失效。
总结
| 方式 | 语义 | 内存管理 | 适用场景 |
|---|---|---|---|
std::unique_ptr | 独占 | 不能拷贝 | 资源独占,如文件句柄 |
std::shared_ptr | 共享 | 计数管理 | 共享资源,如缓存 |
| 拷贝构造 | 独占/共享 | 深拷贝/浅拷贝 | 具体需求 |
| 移动构造 | 独占 | 资源转移 | 避免临时对象开销 |
通过这些方法,我们可以更高效地管理 C++ 中的资源分配和释放,避免内存泄漏和重复释放。
深拷贝(独占)
- 拷贝的是 值,拷贝后 新对象与源对象完全独立。
- 析构一方 不影响 另一方。
浅拷贝(共享)
- 拷贝的是 指针/引用,拷贝后 新对象与源对象共享同一份内存。
- 析构一方后 另一方会受到影响。
为了防止 重复 delete,需要引入 引用计数,只有当 没有任何对象引用这块堆内存时,才释放它。
std::shared_ptr 实现的思路:
std::shared_ptr 通过 内部的引用计数 记录有多少个 shared_ptr 共享同一块内存,只有当 引用计数归零时,才释放资源。
#include <iostream>
#include <memory>using namespace std;void sharedPtrDemo()
{shared_ptr<int> p1 = make_shared<int>(10);{shared_ptr<int> p2 = p1;cout << "引用计数: " << p1.use_count() << endl;} // p2 作用域结束,引用计数减少cout << "引用计数: " << p1.use_count() << endl;
}
相关文章:
C++11QT复习 (七)
智能指针雏形 **Day7-1 智能指针雏形:独占语义与共享语义****1. 独占语义与共享语义****1.1 Circle 类:示例类** **2. 拷贝构造:独占语义(Unique Ownership)****2.1 代码解析** **3. 拷贝构造:共享语义&…...
STM32八股【5】----- TIM定时器
1. TIM定时器分类 STM32 的定时器主要分为以下几类: 高级定时器(Advanced TIM,TIM1/TIM8) 具备 PWM 生成、死区控制、互补输出等高级功能,适用于电机控制和功率转换应用。通用定时器(General-purpose TIM…...
单元测试之Arrange-Act-Assert(简称AAA)
Arrange-Act-Assert(简称AAA)是一种编写单元测试的标准模式,具有清晰的结构和明确的步骤,有助于提高测试的可读性、可维护性和可扩展性。以下是对每个步骤的详细说明: 1. Arrange(准备阶段) 在…...
厘米级定位赋能智造升级:品铂科技UWB技术驱动工厂全流程自动化与效能跃升”
在智能制造中的核心价值体现在高精度定位、流程优化、安全管理等多个维度,具体应用如下: 一、核心技术与定位能力 厘米级高精度定位 UWB技术通过纳秒级窄脉冲信号(带宽超500MHz)实现高时间分辨率,结合…...
C++刷题(四):vector
📝前言说明: 本专栏主要记录本人的基础算法学习以及刷题记录,使用语言为C。 每道题我会给出LeetCode上的题号(如果有题号),题目,以及最后通过的代码。没有题号的题目大多来自牛客网。对于题目的…...
学习记录706@微信小程序+springboot项目 真机测试 WebSocket错误: {errMsg: Invalid HTTP status.}连接不上
我微信小程序springboot项目 真机测试 websocket 总是报错 WebSocket错误: {errMsg: Invalid HTTP status.},总是连接不上,但是开发者工具测试就没有问题。 最后解决方案是编码token,之前是没有编码直接拼接的,原因不详。 consol…...
【虚拟仪器技术】Labview虚拟仪器技术应用教程习题参考答案[13页]
目录 第1章 第2章 第3章 第4章 第5章 第6章 第7章 第8章 第1章 1. 简述虚拟仪器概念。 参考答案:虚拟仪器是借助于强大的计算机软件和硬件环境的支持,建立虚拟的测试仪器面板,完成仪器的控制、数…...
【工作梳理】怎么把f12里面的东西导入到postman
postman左上角导入 结果:...
UE5学习笔记 FPS游戏制作34 触发器切换关卡
文章目录 搭建关卡制作触发器传送门显示加载界面 搭建关卡 首先搭建两个关卡,每个关卡里至少要有一个角色 制作触发器传送门 1 新建一个蓝图,父类为actor,命名为portal(传送门) 2 为portal添加一个staticMesh&#…...
智谱大模型(ChatGLM3)PyCharm的调试指南
前言 最近在看一本《ChatGLM3大模型本地化部署、应用开发和微调》,本文就是讨论ChatGLM3在本地的初步布设。(模型文件来自魔塔社区) 1、建立Pycharm工程 采用的Python版本为3.11 2、安装对应的包 2.1、安装modelscope包 pip install model…...
新专栏预告 《AI大模型应知应会短平快系列100篇》 - 整体规划设计
做个预告,为系统化梳理AI大模型的发展脉络,并为普及AI素养做一点贡献,特给自己制定了一个小目标,3个月内完成交稿。 AI大模型应知应会短平快系列100篇 - 整体规划设计 一、基础知识模块(20篇) 1.1 大模型…...
SwanLab Slack通知插件:让AI训练状态同步更及时
在AI模型训练的过程中,开发者常常面临一个难题:如何及时跟踪训练状态?无论是实验超参数的调整、关键指标的变化,还是意外中断的告警,传统的监控方式往往依赖手动刷新日志或反复检查终端,这不仅效率低下&…...
收集 的 JavaScript 数组方法表格
这个表格可以作为数组方法的快速参考指南 方法名对应版本功能原数组是否改变返回值类型concat()ES5-合并数组,并返回合并之后的新数组nArrayjoin()ES5-使用分隔符,将数组转为字符串并返回nStringpop()ES5-删除最后一位,并返回删除的数据yAny…...
操作系统高频(六)linux内核
操作系统高频(六)linux内核 1.内核态,用户态的区别⭐⭐⭐ 内核态和用户态的区别主要在于权限和安全性。 权限:内核态拥有最高的权限,可以访问和执行所有的系统指令和资源,而用户态的权限相对较低&#x…...
位置编码汇总 # 持续更新
看了那么多还没有讲特别好的,GPT老师讲的不错关于三角函数编码。 一、 手撕transformer常用三角位置编码 GPT说:“低维度的编码(例如,第一个维度)可以捕捉到大的位置差异,而高维度的编码则可以捕捉到小的细…...
电阻(Resistor)详解
一、电阻的定义与核心作用 电阻是电子电路中用于 限制电流、分压、调节信号电平、消耗功率 的基础被动元件,其阻值(Resistance)单位为欧姆(Ω)。其核心作用可归纳为: 限流保护:防止元器件过电流…...
DaVinci Resolve19.1下载:达芬奇调色中文版+安装步骤
如大家所了解的,DaVinci Resolve中文名为达芬奇,是一款专业视频编辑与调色软件。它最初以调色功能闻名,但经过多年发展,已扩展为一套完整的后期制作解决方案,涵盖了剪辑、视觉特效、动态图形和音频后期制作等多个模块。…...
文件IO 2
补充一些用到前面没提到的方法 isDirectory()方法,检查一个对象是否是文件夹,是true不是false isFile()方法,检测一个对象是否为文件,是true不是false 文件的读写操作实践 上一篇大致讲了文件读写操作的基本操作,下面是实践时…...
【Word】批注一键导出:VBA 宏
📌 VBA 宏代码实现 下面是完整的 VBA 代码,支持: 自动创建新文档,并将当前 Word 文档的所有批注导出。批注格式清晰,包括编号、作者、日期和批注内容。智能检测,如果当前文档没有批注,则提示用…...
《深度洞察:MySQL与Oracle中游标的性能分野》
在数据库管理的复杂领域中,游标作为一种强大的工具,用于对数据进行逐行处理,为许多复杂的数据操作提供了解决方案。然而,当涉及到MySQL和Oracle这两大主流数据库时,游标在性能表现上存在着显著的差异。深入理解这些差异…...
LINUX 1
快照 克隆:关机状态下:长时间备份 uname 操作系统 -a 获取所有信息 绝对路径 相对路径 -a -l 列表形式查看 -h 查看版本 相对路径这个还没太搞懂 LS -L LL 简写 显示当前路径 pwd cd 切换到目录 clear 清屏 reboot 重启操作系统...
高效定位 Go 应用问题:Go 可观测性功能深度解析
作者:古琦 背景 自 2024 年 6 月 26 日,阿里云 ARMS 团队正式推出面向 Go 应用的可观测性监控功能以来,我们与程序语言及编译器团队携手并进,持续深耕技术优化与功能拓展。这一创新性的解决方案旨在为开发者提供更为全面、深入且…...
【Windows】win10系统安装.NET Framework 3.5(包括.NET 2.0和3.0)失败 错误代码:0×80240438
一、.NET3.5(包括.NET 2.0和3.0)安装方式 1.1 联网安装(需要联网,能访问微软,简单,很可能会失败) 1.2 离线安装-救急用(需要操作系统iso镜像文件,复杂,成功几率大) 二、联网安装 通过【控制面板】→【程序】→【程序和功能】→【启用或关闭Windows功能】 下载过程…...
蓝桥杯训练士兵
思路:其实每次就是要比较士兵单独训练的价格之和SUM与S的大小,如果 SUM大,那么就减去所有士兵都要训练的次数的最小值,SUM再更新一下,继续比较。 先对士兵的次数按从小到大的次序排序(很重要)&…...
Java基础-27-多态-多态好处和存在的问题
在面向对象编程(OOP)中,多态是一个非常重要的概念。它能够让我们用统一的方式处理不同类型的对象,提升代码的灵活性和可扩展性。Java 作为一种面向对象的编程语言,充分支持多态,并在实际开发中提供了巨大的…...
循环神经网络 - 简单循环网络
本文我们来学习和了解简单循环网络(Simple Recurrent Network,SRN), SRN是一个非常简单的循环神经网络,只有一个隐藏层的神经网络。 简单循环神经网络,也常称为 Elman 网络,是最基本的循环神经网络(RNN&am…...
Linux 企业项目服务器组建(附脚本)
一、架构概述 本方案旨在为企业搭建一套高效、安全的 Linux 服务器架构,包含一台 DNS 服务器,以及一台同时承载 FTP 和 Samba 服务的服务器,满足公司在域名解析、图片存储与共享、文件共享等方面的业务需求。 二、服务器部署 DNS 服…...
Linux 2021韩顺平网课笔记:shell编程
基本介绍 Shell是一个命令行解释器,它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序,用户可以用Shell来启动、挂起、停止甚至是编写一些程序。 Shell脚本的执行方式 格式要求 脚本以 #!bin/bash 开头,表明以bashell…...
软考 中级软件设计师 考点知识点笔记总结 day09 操作系统进程管理
文章目录 4、操作系统基本原理4.1 、进程管理**4.1.1 、进程同步机制****4.1.2 、进程互斥机制****4.1.3 、信号量机制****4.1.4 、PV操作实现前驱操作****4.1.5 、死锁**4.1.6 、银行家算法 4、操作系统基本原理 进程管理 存储管理 文件管理 设备管理 微内核操作系统 操作系…...
大模型和AIGC同质化浪潮下的信息困局与破局之道,面向未来的认知革命
欢迎来到涛涛聊AI。看到网上太多雷同的内容有感后,让AI批判下AI。 一、技术趋同引发的信息生态危机 当前互联网正被海量AI生成内容淹没,这种现象的根源在于技术底层的高度同质化。全球主流大模型90%以上基于相同算法架构开发,采用近似的训练…...
