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

C++代码优化--要求或禁止在堆中产生对象

目录

1.引言

2.栈与堆区别

2.1. 栈(Stack)

2.2. 堆(Heap)

3.限制在堆上分配内存的好处

4.对象在栈上分配内存的方法

4.1. 使用RAII(资源获取即初始化)

4.2. 避免使用new和delete

4.3. 限制对象的生命周期

4.禁止在堆上分配对象的方法

4.1. 将构造函数设为私有或者受保护

4.2. 删除operator new和operator delete

4.3. 使用工厂函数控制对象创建

4.4. 模板技术限制堆分配


1.引言

        在C++代码优化中,内存分配策略(即对象是在栈上还是在堆上分配)对程序的性能和资源管理有着显著影响。合理地要求或禁止在堆中产生对象,可以有效提高程序的效率、减少内存碎片,并增强代码的可维护性。本文将详细探讨如何在C++中要求或禁止对象在堆中分配,并介绍相关的优化技术和最佳实践。

2.栈与堆区别

2.1. 栈(Stack)

  • 分配方式:由编译器自动管理,分配和释放速度极快。

  • 生命周期:对象的生命周期由其作用域决定,超出作用域自动销毁。

  • 大小限制:栈的大小通常较小,过多或过大的栈分配可能导致栈溢出。

  • 访问速度:访问速度快,缓存命中率高。

2.2. 堆(Heap)

  • 分配方式:由程序员手动管理(使用newdelete),也可通过智能指针管理。

  • 生命周期:对象的生命周期由程序员控制,需要手动释放,否则会导致内存泄漏。

  • 大小限制:堆的大小远大于栈,适合分配大对象或数量众多的对象。

  • 访问速度:访问速度相对较慢,且可能导致内存碎片。

3.限制在堆上分配内存的好处

  1. 性能提升:栈分配速度更快,减少动态内存分配的开销。

  2. 内存管理简化:避免手动管理堆内存,减少内存泄漏和悬挂指针的风险。

  3. 缓存优化:栈上对象更容易被CPU缓存命中,提高访问效率。

  4. 资源控制:限制堆分配可以防止程序过度消耗内存资源,提升稳定性。

4.对象在栈上分配内存的方法

4.1. 使用RAII(资源获取即初始化)

RAII是一种C++编程习惯,通过将资源的获取与对象的生命周期绑定,确保资源在对象的构造和析构中被正确管理。这样可以减少对堆分配的需求。

#include <iostream>
#include <vector>class Resource {
public:Resource() { std::cout << "Resource acquired\n"; }~Resource() { std::cout << "Resource released\n"; }void doSomething() { std::cout << "Doing something\n"; }
};void func() {Resource res; // 栈上分配res.doSomething();
} // 自动调用析构函数,释放资源int main() {func();return 0;
}

4.2. 避免使用new和delete

尽量在需要的地方使用栈对象,避免动态分配。使用智能指针(如std::unique_ptrstd::shared_ptr)来管理堆对象,但在可能的情况下,优先使用栈对象。

#include <memory>class MyClass {
public:void doWork() {}
};int main() {MyClass obj; // 栈上分配obj.doWork();// 使用智能指针管理堆对象std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>();ptr->doWork();return 0;
}

4.3. 限制对象的生命周期

通过设计类的接口和生命周期管理,确保对象在栈上分配,并且在作用域结束时自动销毁。

#include <iostream>class ScopedObject {
public:ScopedObject() { std::cout << "ScopedObject created\n"; }~ScopedObject() { std::cout << "ScopedObject destroyed\n"; }void doSomething() { std::cout << "ScopedObject doing something\n"; }
};void process() {ScopedObject obj; // 栈上分配obj.doSomething();
} // 自动销毁int main() {process();return 0;
}

4.禁止在堆上分配对象的方法

4.1. 将构造函数设为私有或者受保护

通过将构造函数设为私有或受保护,可以防止外部直接使用new进行对象创建,仅允许在特定的上下文中创建对象,如工厂函数或友元类。

#include <iostream>class NoHeap {
public:static NoHeap create() {return NoHeap(); // 通过静态成员函数创建对象}void doWork() { std::cout << "NoHeap doing work\n"; }private:NoHeap() { std::cout << "NoHeap constructed\n"; }~NoHeap() { std::cout << "NoHeap destructed\n"; }
};int main() {NoHeap obj = NoHeap::create(); // 只能在栈上分配obj.doWork();// 以下代码将无法编译,因为构造函数是私有的// NoHeap* p = new NoHeap(); // 编译错误return 0;
}

4.2. 删除operator new和operator delete

通过在类中删除operator newoperator delete,可以彻底禁止通过newdelete进行堆分配。

#include <iostream>class NoHeapAlloc {
public:NoHeapAlloc() { std::cout << "NoHeapAlloc constructed\n"; }~NoHeapAlloc() { std::cout << "NoHeapAlloc destructed\n"; }void doWork() { std::cout << "NoHeapAlloc doing work\n"; }// 删除全局和数组版本的operator new和operator deletevoid* operator new(size_t) = delete;void operator delete(void*) = delete;void* operator new[](size_t) = delete;void operator delete[](void*) = delete;
};int main() {NoHeapAlloc obj; // 栈上分配obj.doWork();// 以下代码将无法编译,因为operator new被删除// NoHeapAlloc* p = new NoHeapAlloc(); // 编译错误return 0;
}

4.3. 使用工厂函数控制对象创建

通过工厂函数,仅允许在栈上创建对象,并在工厂函数中返回对象的副本,而不是指针。

#include <iostream>class FactoryControlled {
public:void doWork() { std::cout << "FactoryControlled doing work\n"; }private:// 构造函数私有,防止外部直接创建FactoryControlled() { std::cout << "FactoryControlled constructed\n"; }~FactoryControlled() { std::cout << "FactoryControlled destructed\n"; }// 工厂函数为友元friend FactoryControlled createFactoryControlled();
};// 工厂函数
FactoryControlled createFactoryControlled() {return FactoryControlled();
}int main() {FactoryControlled obj = createFactoryControlled(); // 只能通过工厂函数创建obj.doWork();// 以下代码将无法编译,因为构造函数是私有的// FactoryControlled* p = new FactoryControlled(); // 编译错误return 0;
}

4.4. 模板技术限制堆分配

通过模板编程技术,限制特定类只能在栈上分配。例如,使用CRTP(Curiously Recurring Template Pattern)模式,或者在基类中禁用operator new

#include <iostream>template <typename T>
class StackOnly {
public:void doWork() { std::cout << "StackOnly doing work\n"; }private:// 禁用operator new和operator deletevoid* operator new(size_t) = delete;void operator delete(void*) = delete;
};class MyStackOnly : public StackOnly<MyStackOnly> {
public:MyStackOnly() { std::cout << "MyStackOnly constructed\n"; }~MyStackOnly() { std::cout << "MyStackOnly destructed\n"; }
};int main() {MyStackOnly obj; // 栈上分配obj.doWork();// 以下代码将无法编译,因为operator new被禁用// MyStackOnly* p = new MyStackOnly(); // 编译错误return 0;
}

结合这些方法,可以编写高效、安全且易于维护的C++代码,特别适用于对性能和资源管理有严格要求的应用场景,如游戏开发、高性能服务器和嵌入式系统等。

相关文章:

C++代码优化--要求或禁止在堆中产生对象

目录 1.引言 2.栈与堆区别 2.1. 栈&#xff08;Stack&#xff09; 2.2. 堆&#xff08;Heap&#xff09; 3.限制在堆上分配内存的好处 4.对象在栈上分配内存的方法 4.1. 使用RAII&#xff08;资源获取即初始化&#xff09; 4.2. 避免使用new和delete 4.3. 限制对象的生…...

MybatisPlus入门(六)MybatisPlus-空值处理

一、MybatisPlus-空值处理 1.1&#xff09;问题引入&#xff1a; 在查询中遇到如下情况&#xff0c;有部分筛选条件没有值&#xff0c;如商品价格有最大值和最小值&#xff0c;商品价格部分时候没有值。 1.2&#xff09;解决办法&#xff1a; 步骤一&#xff1a;新建查询实体…...

钉钉内集成第三方免密登录(Vue+.Net)

需要实现的效果就是在钉钉内点击应用能跳转到第三方网站并且免密登录 1.登录钉钉PC端管理后台 2.通过管理后台进去开发者后台 3.应用开发 创建H5微应用 4.应用创建成功后直接点权限管理全部授权 5.设置H5登录地址 6. 应用管理发布 至此需要配置的步骤全部已完成&#xff0c;…...

卷积神经网络实验三:模型优化(1)

作者有话说&#xff1a; 这篇文章写的还是比混乱的。因为本人也是第一次做这样的尝试&#xff0c;虽然接触深度学习有一年了&#xff0c;但是对于模型的优化仅仅是局限于理论上。通过这一次的实验&#xff0c;我对于模型的理解也更深了几分。我不期望这篇文章能帮你能解决多大问…...

STM32F103的CAN通讯接收测试

首先配置CUBEMX 1.打开CUBEMX 设置时钟&#xff0c;由于我没有外部时钟&#xff0c;所以我选择内部时钟&#xff0c;选择8倍频&#xff0c;1分频&#xff0c;APB1时钟频率为32MKHZ,也就是说每秒能够执行 3200 万个时钟周期&#xff0c;1M是每秒执行100万个时钟周期。 2.CAN收…...

【Rust中的智能指针】

Rust中的智能指针 什么是智能指针&#xff1f;什么是Rust中的智能指针&#xff1f;Rust中的智能指针BoxBox的使用场景 Rust中的智能指针Rc与Arcrust中的RefCellrefcell的缺点&#xff1a;rust中的weak先来看看C中的weak_ptr定义代码示例&#xff1a; Deref和Drop 总结 什么是智…...

基于深度学习的社交网络中的社区检测

在社交网络分析中&#xff0c;社区检测是一项核心任务&#xff0c;旨在将网络中的节点&#xff08;用户&#xff09;划分为具有高内部连接密度且相对独立的子群。基于深度学习的社区检测方法&#xff0c;通过捕获复杂的网络结构信息和节点特征&#xff0c;在传统方法基础上实现…...

【Python基础】

一、编程语言介绍 1、分类 机器语言 (直接用 0 1代码编写&#xff09;汇编语言 &#xff08;英文单词替代二进制指令&#xff09;高级语言 2、总结 1、执行效率&#xff1a;机器语言&#xff1e;汇编语言>高级语言&#xff08;编译型>解释型&#xff09; 2、开发效率&…...

【玉米叶部病害识别】Python+深度学习+人工智能+图像识别+CNN卷积神经网络算法+TensorFlow

一、介绍 玉米病害识别系统&#xff0c;本系统使用Python作为主要开发语言&#xff0c;通过收集了8种常见的玉米叶部病害图片数据集&#xff08;‘矮花叶病’, ‘健康’, ‘灰斑病一般’, ‘灰斑病严重’, ‘锈病一般’, ‘锈病严重’, ‘叶斑病一般’, ‘叶斑病严重’&#x…...

【设计模式】如何用C++实现依赖倒置

【设计模式】如何用C实现依赖倒置 一、什么是依赖倒置&#xff1f; 依赖倒置原则&#xff08;Dependency Inversion Principle&#xff0c;DIP&#xff09;是SOLID面向对象设计原则中的一项。它的核心思想是&#xff1a; 高层模块不应该依赖于低层模块&#xff0c;两者都应该…...

使用onnxruntime-web 运行yolov8-nano推理

ONNX&#xff08;Open Neural Network Exchange&#xff09;模型具有以下两个特点促成了我们可以使用onnxruntime-web 直接在web端上运行推理模型&#xff0c;为了让这个推理更直观&#xff0c;我选择了试验下yolov8 识别预览图片&#xff1a; 1. 跨平台兼容性 ONNX 是一种开…...

Gin框架html/vue前端使用hls.js播放/点播m3u8(hls)格式视频

说明 在web应用开发时遇到在线播放m3u8格式视频&#xff0c;由于m3u8是多分片视频&#xff0c;原生video标签无法直接播放&#xff0c;所以需要js对m3u8处理才能播放&#xff0c;网上有很多插件&#xff0c;这里我选择最近简单方法hls.js播放&#xff0c;引入一个js文件即可。…...

HarmonyOS 私仓搭建

1. HarmonyOS 私仓搭建 私仓搭建文档&#xff1a;https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-ohpm-repo-quickstart-V5   发布共享包[https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-har-publish-0000001597973129-V5]…...

Mybatis学习笔记(二)

八、多表联合查询 (一) 多表联合查询概述 在开发过程中单表查询不能满足项目需求分析功能&#xff0c;对于复杂业务来讲&#xff0c;关联的表有几张&#xff0c;甚至几十张并且表与表之间的关系相当复杂。为了能够实业复杂功能业务&#xff0c;就必须进行多表查询&#xff0c…...

Google“Big Sleep“人工智能项目发现真实软件漏洞

据Google研究人员称&#xff0c;该公司的一个人工智能项目足够聪明&#xff0c;能够自行发现现实世界中的软件漏洞&#xff1b;Google的人工智能项目最近在开源数据库引擎 SQLite 中发现了一个之前未知的可利用漏洞。 该公司随后在正式软件发布之前报告了这一漏洞&#xff0c;这…...

npm入门教程5:package.json

一、package.json 文件的作用 依赖管理&#xff1a;列出项目所依赖的包&#xff08;库&#xff09;及其版本&#xff0c;便于其他开发者或自动化工具快速安装和更新这些依赖。元数据描述&#xff1a;提供项目的描述、作者、许可证等元信息&#xff0c;有助于项目的管理和维护。…...

docker-高级(待补图)

文章目录 数据卷(Volume)介绍查看方法删除方法绑定方法匿名绑定具名绑定Bind Mount 数据卷管理 网络bridge(桥接模式 默认)HOST(主机模式)Nonecontainer(指定一个容器进行关联网络共享)自定义(推荐)docker network 命令创建网络docker network create 实例展示-自定义实例展示-…...

Qt 文件目录操作

Qt 文件目录操作 QDir 类提供访问系统目录结构 QDir 类提供对目录结构及其内容的访问。QDir 用于操作路径名、访问有关路径和文件的信息以及操作底层文件系统。它还可以用于访问 Qt 的资源系统。 Qt 使用“/”作为通用目录分隔符&#xff0c;与“/”在 URL 中用作路径分隔符…...

Pandas 数据清洗

1.数据清洗定义 数据清洗是对一些没有用的数据进行处理的过程。很多数据集存在数据缺失、数据格式错误、错误数据或重复数据的情况&#xff0c;如果要使数据分析更加准确&#xff0c;就需要对这些没有用的数据进行处理。 2.清洗空值 DataFrame.dropna(axis0, howany, threshN…...

IO学习笔记

当前需求&#xff0c;希望进行游戏可以保存游戏进度&#xff0c;可以将游戏的进度保存到一个文本文件&#xff0c;每一次打完游戏更新文本内容&#xff0c;下一次打游戏读取游戏进度&#xff0c;这里就涉及到两个知识IO流和File的知识。 File类 概述 java.io.File 类是文件…...

OpenClaw+GLM-4.7-Flash:科研数据收集与处理自动化方案

OpenClawGLM-4.7-Flash&#xff1a;科研数据收集与处理自动化方案 1. 为什么科研需要自动化助手 去年冬天&#xff0c;我在整理一篇跨学科综述论文时&#xff0c;经历了连续三周每天14小时的手动文献筛选和数据提取。当我在凌晨三点对着第237篇PDF文件发呆时&#xff0c;突然…...

别再手动改MTL文件了!一个Python脚本搞定ENVI打开Landsat 8/9 L2影像的报错问题

用Python自动化修复Landsat L2影像的ENVI兼容性问题 遥感数据处理中&#xff0c;Landsat 8/9的L2级别影像在ENVI软件中打开时经常遇到兼容性问题。传统的手动修改MTL文件方法不仅效率低下&#xff0c;还容易出错。本文将介绍一个Python自动化解决方案&#xff0c;帮助您彻底摆脱…...

ncmdumpGUI+解决网易云音乐NCM文件跨设备播放痛点

ncmdumpGUI解决网易云音乐NCM文件跨设备播放痛点 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换&#xff0c;Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 问题场景&#xff1a;被加密的音乐自由 想象这样的场景&…...

用WS2812B打造智能家居氛围灯:STM32音乐频谱+呼吸灯效果实战

用WS2812B打造智能家居氛围灯&#xff1a;STM32音乐频谱呼吸灯效果实战 智能家居的灯光系统早已超越了简单的照明功能&#xff0c;逐渐演变为提升生活品质的重要元素。想象一下&#xff0c;当你结束一天疲惫的工作回到家&#xff0c;灯光随着你喜欢的音乐节奏跳动&#xff0c;或…...

微机原理实验一代码逐行精讲:从‘Hello World’到ASCII转换的底层逻辑

微机原理实验一代码逐行精讲&#xff1a;从‘Hello World’到ASCII转换的底层逻辑 当屏幕上跳出"Hello World!"时&#xff0c;很少有人思考这行文字背后究竟发生了什么。这段经典的汇编代码就像一扇门&#xff0c;推开它你将看到CPU如何与内存对话、中断服务程序如何…...

5分钟搞定ESP32开发:VSCode+ESP-IDF插件极简配置教程

5分钟极速搭建ESP32开发环境&#xff1a;VSCodeESP-IDF全流程指南 在物联网开发领域&#xff0c;ESP32凭借其出色的性价比和丰富的功能接口&#xff0c;已经成为智能硬件开发者的首选平台。但对于刚接触ESP32的开发者来说&#xff0c;传统的环境搭建过程往往充满挑战——从工具…...

帧差法实战避坑:为什么你的运动检测总是有‘鬼影’?三帧差法参数调优全解析

帧差法实战避坑&#xff1a;为什么你的运动检测总是有‘鬼影’&#xff1f;三帧差法参数调优全解析 当你第一次尝试用帧差法实现运动检测时&#xff0c;那种兴奋感可能很快就会被现实浇灭——屏幕上那些模糊的拖影、闪烁的噪点&#xff0c;还有那些明明没有物体移动却不断跳动的…...

ONNX Runtime C++部署踩坑记:GetInputName已弃用,手把手教你改用GetInputNameAllocated

ONNX Runtime C部署实战&#xff1a;从GetInputName到GetInputNameAllocated的平滑迁移指南 在深度学习模型部署的生态系统中&#xff0c;ONNX Runtime凭借其跨平台特性和高性能推理能力&#xff0c;已成为工业界广泛采用的推理引擎。然而&#xff0c;随着其C API的迭代升级&a…...

Anlogic FD工具深度体验:如何用eMCU软核实现SF1芯片的PSRAM控制器设计

Anlogic FD工具实战&#xff1a;基于eMCU软核的PSRAM控制器设计进阶指南 当FPGA工程师需要在资源受限的SF1芯片上实现高性能存储控制时&#xff0c;Anlogic Future Dynasty&#xff08;FD&#xff09;工具链中的eMCU软核与PSRAM控制器组合提供了绝佳的解决方案。不同于基础教程…...

OpenClaw多通道控制:Qwen3-32B-Chat同时响应飞书与网页端指令

OpenClaw多通道控制&#xff1a;Qwen3-32B-Chat同时响应飞书与网页端指令 1. 为什么需要多通道控制&#xff1f; 上周三晚上11点&#xff0c;我正在用OpenClaw的网页控制台整理项目文档&#xff0c;突然飞书弹出同事的紧急需求&#xff1a;"能不能立刻帮我生成上季度销售…...