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

day09了 加油

浅拷贝 指向同一个地址空间

右边不可取地址 左边一定是到了具体的位置

右值引用std:: move

相信大家默认构造函数都没有问题,所以就不贴例子了

浅拷贝构造函数

只负责复制地址,而不是真的把完整的内存给它

#include <iostream>// 浅拷贝是通过默认的复制构造函数来实现的。默认的复制构造函数会逐个复制对象的所有成员变量,但不会复制动态分配的内存。浅拷贝只是复制指针而不复制指针指向的内容。class Shallow {
public:int* data;// 构造函数Shallow(int d) {data = new int(d);}// 浅拷贝构造函数Shallow(const Shallow& source) : data(source.data) {std::cout << "Shallow copy constructor - shallow copy" << std::endl;}// 析构函数~Shallow() {delete data;std::cout << "Destructor freeing data" << std::endl;}
};int main() {Shallow obj1(42);Shallow obj2 = obj1; // 使用浅拷贝构造函数std::cout << "obj1 data: " << *obj1.data << std::endl;std::cout << "obj2 data: " << *obj2.data << std::endl;return 0;
}

深拷贝构造函数

其实跟深拷贝的意思一样,真正的什么都复制

还要分配新的内存

#include <iostream>class Deep {
public:int* data;// 构造函数Deep(int d) {data = new int(d);}// 深拷贝构造函数Deep(const Deep& source) {data = new int(*source.data);std::cout << "Deep copy constructor - deep copy" << std::endl;}// 析构函数~Deep() {delete data;std::cout << "Destructor freeing data" << std::endl;}
};int main() {Deep obj1(42);Deep obj2 = obj1; // 使用深拷贝构造函数std::cout << "obj1 data: " << *obj1.data << std::endl;std::cout << "obj2 data: " << *obj2.data << std::endl;return 0;
}

浅拷贝构造函数的代码会遇到一个问题,就是出现悬空指针,析构的时候会指向同一个指针

而深拷贝就避免了这个问题

为了提升性能,因此就来了新的概念 

移动语义

用移动构造函数和移动赋值运算符。

移动构造函数(Move Constructor)是C++11引入的一种特殊构造函数,

用于实现对象资源的高效转移,而不是复制。

它的引入是为了避免不必要的深拷贝,提高程序性能,特别是当处理临时对象时。

移动构造函数的概念

  • 移动构造函数允许从一个即将销毁的对象(通常是临时对象)中“窃取”资源,而不是复制资源。
  • 移动构造函数接收一个右值引用参数,即将被移动的对象,并将其资源转移到新对象中。
  • 移动构造函数通常与移动赋值运算符一起使用,以实现全面的移动语义。

这里建议直接看例子

移动构造函数的语法

移动构造函数的声明使用右值引用参数(通常是 Type&&,并在实现中转移资源。

#include <iostream>class Mstring {
public:char* data;// 默认构造函数Mstring() : data(nullptr) {std::cout << "Default constructor called" << std::endl;}// 参数构造函数Mstring(const char* str) {if (str) {data = new char[strlen(str) + 1];strcpy(data, str);} else {data = nullptr;}std::cout << "Parameterized constructor called" << std::endl;}// 拷贝构造函数Mstring(const Mstring& source) {if (source.data) {data = new char[strlen(source.data) + 1];strcpy(data, source.data);} else {data = nullptr;}std::cout << "Copy constructor called" << std::endl;}// 移动构造函数Mstring(Mstring&& source) noexcept : data(source.data) {source.data = nullptr;std::cout << "Move constructor called" << std::endl;}// 拷贝赋值运算符Mstring& operator=(const Mstring& source) {if (this == &source)return *this;delete[] data;if (source.data) {data = new char[strlen(source.data) + 1];strcpy(data, source.data);} else {data = nullptr;}std::cout << "Copy assignment operator called" << std::endl;return *this;}// 移动赋值运算符Mstring& operator=(Mstring&& source) noexcept {if (this == &source)return *this;delete[] data;data = source.data;source.data = nullptr;std::cout << "Move assignment operator called" << std::endl;return *this;}// 析构函数~Mstring() {delete[] data;std::cout << "Destructor called" << std::endl;}
};int main() {Mstring str1("Hello");Mstring str2("World");// 使用移动赋值运算符str2 = std::move(str1);std::cout << "After move assignment, str1: " << (str1.data ? str1.data : "nullptr") << std::endl;std::cout << "After move assignment, str2: " << (str2.data ? str2.data : "nullptr") << std::endl;return 0;
}

参数构造函数

参数构造函数是C++类的一种构造函数,

它接受一个或多个参数,

并使用这些参数来初始化类的成员变量。

与默认构造函数(不接受任何参数)相对,

参数构造函数为类的实例提供了一种灵活的初始化方式。

参数构造函数的定义

参数构造函数是在类的定义中声明的构造函数,

其参数列表可以包含一个或多个参数。

通过这些参数,构造函数可以对类的成员变量进行初始化。上面的例子是有体现的

  • 默认构造函数Mstring(),不接受任何参数,初始化成员变量 datanullptr
  • 参数构造函数Mstring(const char* str),接受一个 const char* 参数,用于初始化成员变量 data。如果参数不为空,则分配足够的内存并复制字符串内容。
  • 拷贝构造函数Mstring(const Mstring& source),用于创建一个现有对象的副本,分配新的内存并复制内容。
  • 移动构造函数Mstring(Mstring&& source) noexcept,用于高效地从另一个即将销毁的对象中移动资源,避免了不必要的内存分配和复制。
  • 拷贝赋值运算符:用于将一个对象的内容赋值给另一个现有对象,确保正确地处理动态分配的内存。
  • 移动赋值运算符:用于将一个即将销毁的对象的内容移动到另一个现有对象,避免不必要的内存分配和复制。
  • 析构函数~Mstring(),释放动态分配的内存,避免内存泄漏。
  • main 函数:演示如何使用参数构造函数创建对象,以及如何使用移动构造函数进行对象移动。

内存提前分配

内存提前分配(Pre-allocation)是指在对象或数据结构初始化时提前分配所需的内存,以减少运行时的分配开销。这在需要处理大量数据或频繁分配和释放内存的场景中特别有用。

参数构造函数中的内存提前分配示例

下面是一个改进的 Mstring 类,展示了如何在参数构造函数中提前分配内存。

#include <iostream>class Array {
private:int* data;size_t size;public:// 参数构造函数:提前分配内存Array(size_t size) : size(size) {data = new int[size]; // 提前分配内存std::cout << "Constructor: Allocated memory for " << size << " integers." << std::endl;}// 析构函数:释放内存~Array() {delete[] data;std::cout << "Destructor: Freed allocated memory." << std::endl;}// 获取数组大小size_t getSize() const {return size;}// 获取数组元素(带边界检查)int getElement(size_t index) const {if (index < size) {return data[index];} else {throw std::out_of_range("Index out of range");}}// 设置数组元素(带边界检查)void setElement(size_t index, int value) {if (index < size) {data[index] = value;} else {throw std::out_of_range("Index out of range");}}
};int main() {// 使用参数构造函数创建一个大小为10的数组Array arr(10);// 设置数组中的元素for (size_t i = 0; i < arr.getSize(); ++i) {arr.setElement(i, i * 2);}// 获取并打印数组中的元素for (size_t i = 0; i < arr.getSize(); ++i) {std::cout << "Element at index " << i << ": " << arr.getElement(i) << std::endl;}// arr对象超出作用域时,会自动调用析构函数释放内存return 0;
}

内存重复利用

1.分配一块内存2构建对象3使用对象4析构对象5销毁内存

1.优先使用dowhile循环

压栈的开销非常大,因此避免重复调用

面向对象和面向过程的区别

面向过程和面向对象的区别-CSDN博客

什么是内联函数

函数移除不必要的多态性 减省空间

性能在面向对象中最顶的

swich 跳转很快

简化表达式+位移算法

IO优化

Vector

list

set/multiset

map/Multiset

选择策略

性能分析工具

Asan

实现原理: 编译的时候。。。方式

Gprof

Valgrind

Perf

能看到函数调用次数

系统资源对性能的影响

进程选取

更新当前任务虚拟时间

异构cpu+多频率带

内存管理

相关文章:

  • 基于weixin小程序乡村旅游系统的设计
  • Windows系统安装NVM,实现Node.js多版本管理
  • MATLAB将两个折线图画在一个图里
  • golang项目中gorm框架的配置和具体使用
  • C# 计算椭圆上任意一点坐标
  • 408第二轮复习记录 计算机组成原理(第一章 计算机系统概述)
  • 【高性能服务器】多进程并发模型
  • 【STM32HAL库学习】通信方式:USART、IIC、SPI
  • 如何快速使用JNI
  • Docker在windows上使用vscode远程连接容器
  • 23种设计模式【创建型模式】详细介绍之【单例模式】
  • LabVIEW项目外协时选择公司与个人兼职的比较
  • 工业路由器与家用路由器的区别
  • 4、音视频封装格式---FLV
  • 深度学习之半监督学习:一文梳理目标检测中的半监督学习策略
  • 【407天】跃迁之路——程序员高效学习方法论探索系列(实验阶段164-2018.03.19)...
  • ES6系列(二)变量的解构赋值
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • java概述
  • JS基础篇--通过JS生成由字母与数字组合的随机字符串
  • js正则,这点儿就够用了
  • Koa2 之文件上传下载
  • MySQL Access denied for user 'root'@'localhost' 解决方法
  • Python 基础起步 (十) 什么叫函数?
  • Rancher如何对接Ceph-RBD块存储
  • spring boot 整合mybatis 无法输出sql的问题
  • spring boot下thymeleaf全局静态变量配置
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • 创建一个Struts2项目maven 方式
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • 解析带emoji和链接的聊天系统消息
  • 类orAPI - 收藏集 - 掘金
  • 使用 Node.js 的 nodemailer 模块发送邮件(支持 QQ、163 等、支持附件)
  • 王永庆:技术创新改变教育未来
  • 在Unity中实现一个简单的消息管理器
  • - 转 Ext2.0 form使用实例
  • Prometheus VS InfluxDB
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • # linux 中使用 visudo 命令,怎么保存退出?
  • # Swust 12th acm 邀请赛# [ K ] 三角形判定 [题解]
  • #HarmonyOS:软件安装window和mac预览Hello World
  • #QT(串口助手-界面)
  • (04)odoo视图操作
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (二十一)devops持续集成开发——使用jenkins的Docker Pipeline插件完成docker项目的pipeline流水线发布
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (附源码)ssm户外用品商城 毕业设计 112346
  • (更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)
  • (四)Controller接口控制器详解(三)
  • (一)Kafka 安全之使用 SASL 进行身份验证 —— JAAS 配置、SASL 配置
  • (转) SpringBoot:使用spring-boot-devtools进行热部署以及不生效的问题解决
  • (转)我也是一只IT小小鸟
  • *上位机的定义
  • .gitignore文件—git忽略文件